Jump to content

User:SD0001/RFUD-helper.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by SD0001 (talk | contribs) at 19:50, 28 November 2019. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/**
 *
 * Script to easily respond to requests made at [[Wp:Requests for undeletion]]
 * (WP:RFUD). When accepting a request, the script would do the following:
 * - Post a response below the request
 * - Undelete the page
 * - Remove any deletion tags from the page
 * - Undelete the talk page if it existed
 * - If is a WT:AFC subpage, move it to draft namespace
 * - Adds {{Old AfD}} to talk page if undoing an AfD soft deletion
 * - Offer to userfy the page instead of restoring to source
 *
 */

// <nowiki>
// jshint maxerr: 999

$.when(
	mw.loader.using([ 'mediawiki.util', 'mediawiki.api', 'mediawiki.Title', 'ext.gadget.morebits' ]),
	$.ready
).then(function() {


if (mw.config.get('wgPageName') !== 'Wikipedia:Requests_for_undeletion') {
	return;
}


// Until the patch to morebits is accepted, see #646
Morebits.status.actionCompleted = function(text) {
	var node = document.createElement( 'div' );
	node.appendChild( document.createElement('span') ).appendChild( document.createTextNode( text ) );
	node.className = 'tw_status_info';
	if (Morebits.status.root) {
		Morebits.status.root.appendChild( node );
	}
};


var rfud = {};
window.rfud = rfud;

rfud.advert = ' ([[User:SD0001/RFUD-helper|rfud-helper]])';
Morebits.wiki.api.setApiUserAgent('[[w:User:SD0001/RFUD-helper.js]]');

var pageName;

var params = {};
rfud.params = params;

rfud.callback = function(e) {
	e.preventDefault();
	pageName = e.target.parentElement.childNodes[1].title.slice(17).replace(/_/g,' ');

	var template_element = e.target.parentElement.parentElement.parentElement;
	var header_element = template_element.previousElementSibling;
	while (header_element.tagName !== 'H2') {
		header_element = header_element.previousElementSibling;
	}
	rfud.sectionName = header_element.firstChild.textContent;
	if (rfud.sectionName === '') {
		rfud.sectionName = header_element.firstChild.nextElementSibling.textContent;
	}

	var buttonResponse = e.target.classList[1].slice('rfud-'.length);

	var Window = new Morebits.simpleWindow( 700, 500 );
	Window.setTitle( "Respond to undeletion request of " + pageName );
	Window.setScriptName( "RFUD helper" );
	Window.addFooterLink( "Administrator instructions", "Wikipedia:Requests for undeletion/Administrator instructions" );
	// Window.addFooterLink( "Script documentation", "WP:RFUDHELPER" );

	var form = new Morebits.quickForm( rfud.evaluate );

	if (pageName === 'Page name goes here') {
		form.append({
			type: 'div',
			label: Morebits.htmlNode('div', 'Caution: Accepting this will undelete "Page name goes here", please fix the template usage before proceeding.', 'red')
		});
	}
	// pageName will never have underscores as it part of the mediawiki-generated link title
	// rfud.sectionName could have underscores if user entered them, hence normalize while comparing
	else if (pageName !== rfud.sectionName.replace(/_/g, ' ')) {
		form.append({
			type: 'div',
			label: Morebits.htmlNode('div', 'Note: page name used in template is different from the section name', '#d7280e')
		});
	}

	var field = form.append({
		type: 'field',
		label: 'Response'
	});

	field.append({
		type: 'radio',
		name: 'response',
		list: [
			{
				label: 'Accept',
				value: 'accept',
				checked: buttonResponse === 'accept'
			},
			{
				label: 'Decline',
				value: 'decline',
				checked: buttonResponse === 'decline'
			}
		],
		event: rfud.toggleResponse
	});

	form.append( {
		type: 'field',
		label: 'Work area',
		name: 'work_area'
	} );

	var previewlink = document.createElement( 'a' );
	previewlink.addEventListener('click', function() {
		rfud.preview(result);  // `result` is defined below
	});

	previewlink.style.cursor = "pointer";
	previewlink.textContent = 'Preview';
	form.append( { type: 'div', id: 'rfudpreview', label: [ previewlink ] } );
	form.append( { type: 'div', id: 'rfud-previewbox', style: 'display: none' } );

	form.append( { type:'submit' } );

	var result = form.render();
	Window.setContent(result);
	Window.display();
	$(result).find('textarea').css('font-size', '130%');

	result.previewer = new Morebits.wiki.preview(document.getElementById('rfud-previewbox'));

	// Init the controls
	var evt = document.createEvent( "Event" );
	evt.initEvent( 'change', true, true );
	result.response[ buttonResponse === 'accept' ? 0 : 1 ].dispatchEvent( evt );

};

rfud.toggleResponse = function(e) {
	var form = e.target.form;
	var work_area;

	if (e.target.value === 'accept') {

		work_area = new Morebits.quickForm.element({
			type: 'field',
			label: 'Accept request',
			name: 'work_area'
		});

		var permanent_section_link = 'Special:Permalink/' + mw.config.get('wgRevisionId') + '#' + rfud.sectionName;
		work_area.append({
			type: 'input',
			label: 'Undeletion summary',
			name: 'logsummary',
			tooltip: 'Summary for the deletion log',
			size: '66px',
			value: 'Undelete per [[' + permanent_section_link + '|request]] at [[WP:RFUD]]'
		});

		work_area.append({
			type: 'checkbox',
			list: [ {
				label: 'Userfy this page',
				name: 'userfy',
				value: 'userfy',
				checked: false,
				subgroup: [ {
					type: 'input',
					label: 'Userfy to: ',
					name: 'page',
					size: '60px',
					tooltip: 'User page to which the page is to be moved',
					value: 'User:USERNAME/' + pageName.replace(/^Draft:/, '')
							.replace(/^Wikipedia talk:Articles for creation\//, '')
				}, {
					type: 'checkbox',
					list: [ {
						label: 'Suppress redirect',
						name: 'sredr',
						checked: true
					} ]
				} ],
				event: function(e) {
					if (e.target.checked) {
						var userfypagefield = form['userfy.page'];
						if (userfypagefield.value.includes('USERNAME')) {
							userfypagefield.setSelectionRange('User:'.length, 'User:USERNAME'.length);
							userfypagefield.focus();
						}

						form.template.value = '{{UND|userfy}}';

						if (form.movetodraft) {
							form.movetodraft.checked = false;
							form.movetodraft.disabled = true;
						} else if (form.undeletetalk) {
							form.undeletetalk.checked = false;
							form.undeletetalk.disabled = true;
						}
					} else {
						form.template.value = '{{UND|done}}';
						//$('.UNDtemplateinput').remove(); // remove deleting admin prompt from {{UND|userA7}}
						$('.UNDtemplateinput').parent().remove();
						if (form.movetodraft) {
							form.movetodraft.disabled = false;
						} else if (form.undeletetalk) {
							form.undeletetalk.disabled = false;
						}
					}
				}
			} ]
		});

		if (! mw.Title.newFromText(pageName).isTalkPage()) {
			work_area.append({
				type: 'checkbox',
				list: [ {
					label: 'Undelete talk page if it existed',
					name: 'undeletetalk',
					value: 'undeletetalk',
					checked: true
				} ]
			});
		}

		if (pageName.startsWith('Wikipedia talk:Articles for creation/')) {
			work_area.append({
				type: 'checkbox',
				list: [ {
					label: 'Move to draft namespace',
					name: 'movetodraft',
					value: 'movetodraft',
					checked: true
				} ]
			});
		}

	} else if (e.target.value === 'decline') {

		work_area = new Morebits.quickForm.element({
			type: 'field',
			label: 'Decline request',
			name: 'work_area'
		});

	}

	var template_responses = work_area.append({
		type: 'select',
		label: 'Select a template response: ',
		name: 'template',
		event: rfud.responseTemplateChanged
	});

	$.each(rfud.template_responses[e.target.value], function(i, el) {
		template_responses.append({
			type: 'option',
			value: i,
			label: (i ? (i + ': ') : '') + el,
			selected: /^(Done|Not done)$/.test(el)
		});
	});

	work_area.append({
		type: 'textarea',
		label: 'Comments',
		tooltip: 'Any comments in addition to the template response',
		name: 'comments'
	});


	var old_area = form.work_area;
	var result = work_area.render();
	old_area.replaceWith(result);


};

rfud.template_responses = {
	accept: {
		'' : "No template response",
		'{{UND|done}}' : "Done",
		'{{UND|prod}}' : "contested proposed deletion",
		'{{UND|g13}}' : "draft deleted under G13",
		'{{UND|afc}}' : "for G13s where {{AFC submission}} was used and the draft was submitted and declined",
		'{{UND|afc-ns}}' : "for G13s where {{AFC submission}} was used and where the draft was never submitted",
		'{{UND|g13-draft}}' : "for G13s of draft namespace pages never part of the AfC process",
		'{{UND|userfy}}' : "Userfied",
		'{{UND|userA7}}' : "Userfied A7 article, contact admin before moving back" // has subgroup

	},
	decline: {
		'' : "No template response",
		'{{UND|notdone}}' : "Not done",
		'{{UND|notdone2}}' : "Not done and will not be done",
		'{{UND|2nd}}' : "Was undeleted once, not worked on (soft-decline)",
		'{{UND|doesnotexist}}' : "No deleted page with this name",
		'{{UND|notdonecompany}}' : "Company article failing NCORP",
		'{{UND|notdoneperson}}' : "Biographical article failing NBIO",
		'{{UND|inappropriate}}': "Inappropriate topic for Wikipedia",
		'{{UND|g11}}' : "Blatant advertisement",
		'{{UND|discussion}}' : "Article deleted at a discussion", // has subgroup
		'{{UND|csd}}' : "Article deleted per CSD criteria", // has subgroup
		'{{UND|copyvio}}' : "Copyright violation" // has subgroup

	}
};

rfud.responseTemplateChanged = function(e) {
	var template = e.target.value;
	$('.UNDtemplateinput').parent().remove();

	var newInput;
	if (template === '{{UND|discussion}}') {
		var newInput1 = new Morebits.quickForm.element({
			type: 'input',
			label: 'Discussion: ',
			name: 'discussion',
			size: '70px',
			className: 'UNDtemplateinput',
			value: 'Autofilling...'
		});
		var newInput2 = new Morebits.quickForm.element({
			type: 'input',
			label: 'Closing admin: ',
			name: 'closingadmin',
			className: 'UNDtemplateinput',
			value: 'Autofilling...'
		});
		$(e.target.form).find('h5').before(newInput1.render(), newInput2.render());
	} else if (template === '{{UND|csd}}' || template === '{{UND|userA7}}') {
		newInput = new Morebits.quickForm.element({
			type: 'input',
			label: 'Deleting admin: ',
			name: 'deletingadmin',
			className: 'UNDtemplateinput',
			value: 'Autofilling...'
		});
		$(e.target.form).find('h5').before(newInput.render());
	} else if (template === '{{UND|copyvio}}') {
		newInput = new Morebits.quickForm.element({
			type: 'input',
			label: 'Copyvio source: ',
			name: 'copyviosource',
			size: '70px',
			className: 'UNDtemplateinput'
		});
		$(e.target.form).find('h5').before(newInput.render());
	}

	if (template === '{{UND|userfy}}' || template === '{{UND|userA7}}') {
		if (e.target.form.userfy.checked === false) {
			e.target.form.userfy.click();
			e.target.value = template; // the click above will reset select value to {{UND|userfy}}
		}
	}

	if (template === '{{UND|csd}}' || template === '{{UND|userA7}}') {
		// Auto-fill the name of deleting admin by parsing the deletion log
		var admininputbox = $('input.UNDtemplateinput[name=deletingadmin]')[0];
		$.ajax(mw.util.getUrl('Special:Log', { type: 'delete', subtype: 'delete', page: pageName }))
		.done(function(html) {
			var userlink = $(html).find('.mw-logline-delete .mw-userlink')[0];
			if (userlink) {
				admininputbox.value = userlink.textContent;
			} else {
				admininputbox.value = '';
			}
		})
		.fail(function() {
			admininputbox.value = '';
		});
	} else if (template === '{{UND|discussion}}') {
		// Auto-fill parameters by parsing the deletion log
		var xfdinputbox = $('input.UNDtemplateinput[name=discussion]')[0];
		var closingadmininputbox = $('input.UNDtemplateinput[name=closingadmin]')[0];
		$.ajax(mw.util.getUrl('Special:Log', { type: 'delete', subtype: 'delete', page: pageName }))
		.done(function(html) {
			var xfd, closingadmin;
			$(html).find('.mw-logline-delete .comment a').each(function() {
				if (/^Wikipedia:(?:Articles|Redirects|Templates|Categories|Files|Miscellany) for (?:deletion|discussion)/.test(this.title)) {
					xfd = this.title;
					closingadmin = $(this).parent().parent().find('.mw-userlink')[0].textContent;
					return false; // break
				}
			});
			xfdinputbox.value = xfd || '';
			closingadmininputbox.value = closingadmin || '';
		})
		.fail(function() {
			xfdinputbox.value = '';
			closingadmininputbox.value = '';
		});
	}
};

rfud.getResponseWikitext = function(forPreview) {
	var templatetext = params.template.replace(/^\{\{/, '{{subst:');
	var parameterText = '';
	switch (params.template) {
		case '{{UND|discussion}}':
			parameterText = '|' + params.discussion + '|' + params.closingadmin;
			break;
		case '{{UND|csd}}':
			parameterText = '|' + params.deletingadmin;
			break;
		case '{{UND|copyvio}}':
			parameterText = '|' + params.copyviosource;
			break;
		case '{{UND|userfy}}':
			parameterText = '|' + params['userfy.page'];
			break;
		case '{{UND|userA7}}':
			parameterText = '|' + params['userfy.page'] + '|' + params.deletingadmin;
			break;
	}
	templatetext = templatetext.replace('}}', parameterText + '}}');

	var separator = '';
	if (params.comments) {
		// these templates don't have any text (other than bolded stuff)
		if (params.template === '{{UND|done}}' ||
			params.template == '{{UND|notdone}}' ||
			params.template === '{{UND|notdone2}}') {
			separator = ' ';
		} else {
			separator = '\n\n';
			if (!forPreview) {
				separator += ':';
			}
		}
	}

	var text = (forPreview ? '' : '\n:') + (templatetext ? (templatetext + separator) : '') + params.comments + ' ~~~~';
	return text;
};

rfud.preview = function(result) {
	params = {};
	$(result).find('input, select, textarea').each(function(_i, e) {
		params[e.name] = (e.type === 'checkbox' ? e.checked : e.value);
	}); // params is not set fully correctly, but this is ok as the incorrectly set fields are not required in preview
	result.previewer.beginRender(rfud.getResponseWikitext(true), "API"); // Force wikitext
};

rfud.evaluate = function(e) {

	var form = e.target;

	params = {};
	params.response = form.response.value; // radio input
	$(form).find('input, select, textarea').each(function(_i, e) {
		if (e.type === 'radio') return true;
		if (e.disabled) return true;
		params[e.name] = (e.type === 'checkbox' ? e.checked : e.value);
	});

	if (!params.template && !params.comments) {
		alert('Please select a template response or add a comment');
		return;
	}

	if (params['userfy.page'] && params['userfy.page'].includes('USERNAME')) {
		alert('Please replace "USERNAME" with a valid username');
		return;
	}

	// disable submit of this form only, leaving any other open morebits forms untouched
	$(form).parent().parent().find('.morebits-dialog-buttons')[0].disabled = true;
	Morebits.status.init(form);

	// Never getting called for some reason, window doesn't autoclose
	Morebits.wiki.actionCompleted.event = function() {
		// Morebits.wiki.actionCompleted.notice = "Completed, closing window in a second...";
		// Morebits.status.actionCompleted( Morebits.wiki.actionCompleted.notice );
		// window.setTimeout(function() {
		// 	$(form).parent().prev().find('a').click(); // click close button
		// 	window.location.hash = rfud.sectionName;
		// }, 1000);
	};

	if (params.response === 'accept') {
		var p = new Morebits.wiki.page(pageName, 'Undeleting ' + pageName);
		p.setEditSummary(params.logsummary + rfud.advert);
		p.undeletePage(function onUndeleteSuccess(e) {
			e.getStatusElement().info('Done');
			rfud.doExtras(e.parent); // e = apiobj, e.parent = pagobj
		}, function onUndeleteFailure(e) {
			// XXX: show this error only when the api tells so, will need morebits pull merged first
			e.getStatusElement().warn("Page already exists or was already undeleted");
			rfud.doExtras(e); // e = pageobj, change to e.parent after #679 is merged
		});
	} else {
		rfud.addResponse();
	}

};

rfud.doExtras = function(pageobj) {

	// UNDELETE TALK PAGE
	if (params.undeletetalk) {
		// code adapted from [[Mediawiki:Gadget-Twinklebatchdelete.js]]
		var talkpagename = mw.Title.newFromText(pageName).getTalkPage().getPrefixedText();
		var statelem = new Morebits.status('Talk page');
		var query = {
			'action': 'query',
			'prop': 'deletedrevisions',
			'drvprop': 'ids',
			'drvlimit': 1,
			'titles': talkpagename
		};
		new Morebits.wiki.api('Checking for deleted revisions', query, function talk_page( apiobj ) {
			var xml = apiobj.responseXML;
			var exists = $(xml).find('page:not([missing])').length > 0;
			var delrevs = $(xml).find('rev').attr('revid');

			if (!delrevs) {
				statelem.info('No deleted revisions found');
				rfud.addOldAfd();   // XXX: this is pathetic, find some better way of organising code
				return;
			}
			if (exists) {
				statelem.update('Already exists');
				rfud.addOldAfd();
				return;
			}

			statelem.unlink();
			var talkpage = new Morebits.wiki.page(apiobj.query.titles, "Talk page");
			talkpage.setEditSummary('Undeleting [[Help:Talk page|talk page]] of "' + pageName + '"' + rfud.advert);
			talkpage.undeletePage(rfud.addOldAfd);
		}, statelem).post();
	}


	// USERFY
	if (params.userfy) {
		pageobj = new Morebits.wiki.page(pageName, 'Userfying to ' + params['userfy.page']);
		pageobj.setMoveDestination(params['userfy.page']);
		pageobj.setMoveSuppressRedirect(params.sredr);
		pageobj.setEditSummary('Userfying' + rfud.advert);
		pageobj.move(function onUserfySuccess() {
			pageobj.getStatusElement().info('Done');
			rfud.removeDeletionTags(params['userfy.page']);
		}, function onUserfyFailure(e) {
			var statelem = pageobj.getStatusElement();
			if (e.errorCode === 'articleexists') {
				Morebits.wiki.numberOfActionsLeft++; // hold dialog from closing //

				var skip_button = Morebits.htmlNode('button', 'Skip move');
				skip_button.addEventListener('click', function() {
					Morebits.wiki.numberOfActionsLeft--; // allow dialog to close //
					statelem.warn('skipped following name conflict');
				});

				var newUserfy = $('<input>').attr('type', 'text')[0];
				var new_button = $('<button>').text('OK').click(function() {
					Morebits.wiki.numberOfActionsLeft--;
					var newTitle = newUserfy.value;
					pageobj.setMoveDestination(newTitle);
					pageobj.setMoveSuppressRedirect(params.sredr);
					pageobj.move(function() {
						statelem.info(['userfied to ' + newTitle + ' instead. ',
							Morebits.htmlNode('span', 'Please update your response to reflect the new page name', 'red')]);
						rfud.removeDeletionTags(newTitle);
					});
				});
				statelem.warn([ 'A user page of that name already exists, enter new user page name or skip ',
					newUserfy, new_button[0], skip_button ]);
			}
		});
	}


	// MOVE WT:AFC PAGES TO DRAFT: SPACE
	if (params.movetodraft) {
		pageobj = new Morebits.wiki.page(pageName, 'Moving page to draft namespace');
		pageobj.setMoveDestination(pageName.replace('Wikipedia talk:Articles for creation/', 'Draft:'));
		pageobj.setEditSummary('Moving to new location for drafts' + rfud.advert);
		pageobj.move(function onAfcMoveSuccess() {
			pageobj.getStatusElement().info('Done');
			rfud.removeDeletionTags(pageName.replace('Wikipedia talk:Articles for creation/', 'Draft:'));
		}, function onAfcMoveFailure(e) {
			if (e.errorCode === 'articleexists') {
				pageobj.getStatusElement().warn('A draft page of that name already exists, skipping...');
				Morebits.wiki.numberOfActionsLeft++; // prevent dialog from closing //
				rfud.removeDeletionTags(pageName);
			}
		});
	}


	// REMOVE DELETION TAGS
	if (!params.userfy && !params.movetodraft) {
		rfud.removeDeletionTags(pageName);
	}


	// ADD OLD XFD TO TALK PAGE IF PREVIOUSLY DELETED AT AFD
	if (!params.undeletetalk) {
		rfud.addOldAfd();
	}


	// ADD RESPONSE AT WP:RFUD
	rfud.addResponse();

};

rfud.addOldAfd = function addOldAfd() {
	$.ajax(mw.config.get('wgServer') + '/w/index.php?title=Special:Log/delete&page=' + pageName).then(function(html) {
		var afdLink = $(html).find('#mw-content-text ul .mw-logline-delete .comment a[href^="/wiki/Wikipedia:Articles_for_deletion"]')[0];
		if (!afdLink) {
			return;
		}

		var afdPage = afdLink.title;
		var startStatus = new Morebits.status('Adding {{Old AfD}} to talk page', 'Getting data', 'status');

		var resultPromise = new mw.Api().parse(new mw.Title(afdPage));
		var datePromise = new mw.Api().get({
			action: 'query',
			prop: 'revisions',
			titles: afdPage,
			rvprop: 'timestamp',
			rvlimit: '1',
			rvdir: 'newer'
		});

		$.when(datePromise, resultPromise).then(function(json, parsedPage) {
			var tagtext = '{{Old AfD|page=' + afdPage;
			if (json && json[0] && json[0].query && json[0].query.pages) {
				var timestamp = Object.values(json[0].query.pages)[0].revisions[0].timestamp;
				var d = new Date(timestamp);
				var date = d.getUTCDate() + ' ' + d.getUTCMonthName() + ' ' + d.getUTCFullYear();
				tagtext += '|date=' + date;
			}
			if (parsedPage) {
				var boldedResult = $(parsedPage).find('b')[1].textContent;
				tagtext += "|result='''" + boldedResult + "'''";
			}
			tagtext += '}}\n';

			startStatus.unlink();
			var talkpage = new mw.Title(pageName).getTalkPage().toText();
			var pageobj = new Morebits.wiki.page(talkpage, 'Adding {{Old AfD}} to talk page');
			pageobj.setPrependText(tagtext);
			pageobj.setEditSummary('Adding {{Old AfD}} after undeletion' + rfud.advert);
			pageobj.prepend();

		});
	});
};

rfud.removeDeletionTags = function removeDeletionTags(currentPageName) {
	var pageobj = new Morebits.wiki.page(currentPageName, 'Removing deletion tags from page if any');

	pageobj.load(function(pageobj) {
		var pageText = pageobj.getPageText();
		var statelem = pageobj.getStatusElement();

		var newPageText = pageText.replace(
			// Regex adapted from [[Mediawiki:Gadget-friendlytag.js]]
			new RegExp(
				// leading whitespace
				'^\\s*' +
				// capture template(s)
				'(?:((?:\\s*' +
				// AfD
				'(?:<!--.*AfD.*\\n\\{\\{(?:Article for deletion\\/dated|AfDM).*\\}\\}\\n<!--.*(?:\\n<!--.*)?AfD.*(?:\\s*\\n))?|' + // trailing whitespace/newline needed since this subst's a newline
				// CFD
				'<!-- BEGIN CFD TEMPLATE -->[\\s\\S]*?<!-- END CFD TEMPLATE -->|' +
				// begin template format
				'\\{\\{\\s*(?:' +
					// CSD
					'db|delete|db-.*?|speedy deletion-.*?|di-.*?|' +
					// PROD
					'(proposed deletion|prod blp|book-prod)\\/dated(?:\\s+\\|(?:concern|user|timestamp|help).*)+|' +
					// sometimes under a CSD or AfD
					'|salt|proposed deletion endorsed' +
					// MFD/FFD
					'|mfd|ffd' +
				// end main template name
				')\\s*' +
				// template parameters
				'(\\|(?:\\{\\{[^{}]*\\}\\}|[^{}])*)?' +
				// end template format
				'\\}\\})+' +
				// end capture
				'(?:\\s*\\n)?)' +
				// trailing whitespace
				'\\s*)?',
			'i'), ''
		);

		var changed = false;

		// RFD
		if (/#invoke:RfD/.test(newPageText)) {
			newPageText = newPageText.replace(/\{\{.*?#invoke:RfD[\s\S]*?\|content=\n([\s\S]*?)<!-- Don.*?-->\n?\}\}/, '$1');
			changed = true;
		}

		// TFD
		else if (/Template for discussion\/dated/.test(newPageText)) {
			newPageText = newPageText.replace(/\{\{Template for discussion\/dated.*?(\{\{#invoke:Noinclude.*?\}\})?\}\}/, '');
			changed = true;
		}

		if (changed || newPageText !== pageText) {
			pageobj.setPageText(newPageText);
			pageobj.setEditSummary('Removing deletion tags after undeletion' + rfud.advert);
			pageobj.save();
		} else {
			statelem.info('None found');
		}

	});
};

rfud.addResponse = function rfudAddResponse() {

	var sectionNumber;

	// Get section number by scraping the html of the TOC
	var sectionFound = false;
	$('.toctext').each(function(_i, e) {
		if ( Morebits.string.toUpperCaseFirstChar(e.textContent.replace(/_/g,' ')) === rfud.sectionName ) {
			sectionNumber = parseInt(e.previousElementSibling.textContent);
			sectionFound = true;
			return false; // break
		}
	});
	if (!sectionFound) {
		new Morebits.status('Saving response').warn('Unable to find section.');
		Morebits.status.printUserText(rfud.getResponseWikitext(true), "Your response is provided below, which you may save manually:");
		Morebits.wiki.numberOfActionsLeft++; // prevent dialog from closing //
		return;
	}

	var appendtext = rfud.getResponseWikitext();
	var editsummary = '/* ' + rfud.sectionName + ' */ ' + (params.response === 'accept' ? 'Accepting' : 'Declining') + ' request' + rfud.advert;

	var rfudpage = new Morebits.wiki.page('Wikipedia:Requests for undeletion', 'Saving response');
	rfudpage.setPageSection(sectionNumber);
	rfudpage.setAppendText(appendtext);
	rfudpage.setEditSummary(editsummary);
	rfudpage.setMaxConflictRetries(4);  // Account for admins responding to multiple requests simultaneously
	rfudpage.append(function onAppendSuccess(pageobj) {
		// Reload the section html
		var statelem = pageobj.getStatusElement();
		var reloadApi = new Morebits.wiki.api('Done, reloading section', {
			action: 'parse',
			page: 'Wikipedia:Requests for undeletion',
			section: sectionNumber,
		}, function onReloadSuccess(apiobj) {
			var html = $(apiobj.responseXML).find('text').text().replace(/&lt;/g, '<').replace(/&gt;/g, '>');
			var header = $($('.mw-headline')[sectionNumber - 1].parentElement);
			header.nextUntil('h2').remove();
			header.replaceWith($(html));
			statelem.info('Done, section reloaded');
		}, statelem);
		reloadApi.post();
	});
};

// Add Accept/Decline button
$('li .sysop-show a').each(function(_i, e) {

	var rfudhelperlink_accept = Morebits.htmlNode('a', 'Accept');
	rfudhelperlink_accept.href = '#';
	rfudhelperlink_accept.className = 'rfud-helper-button rfud-accept';
	rfudhelperlink_accept.addEventListener('click', rfud.callback);

	var rfudhelperlink_decline = Morebits.htmlNode('a', 'Decline');
	rfudhelperlink_decline.href = '#';
	rfudhelperlink_decline.className = 'rfud-helper-button rfud-decline';
	rfudhelperlink_decline.addEventListener('click', rfud.callback);

	e.after(document.createTextNode(' | '), rfudhelperlink_accept,
		document.createTextNode(' | '), rfudhelperlink_decline);
});


});
// </nowiki>