User:Evad37/TFDcloser/sandbox.js

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.
// <nowiki>
//global vars
var TFDpath = "Wikipedia:Templates for discussion/Log/";

/* == Main function == */
$( function($) {

// Only run in TFD/subpages, excluding holding cell
	var thispage = mw.config.get( 'wgPageName' );
	if ( !thispage.includes("Templates_for_discussion") || thispage.includes("Templates_for_discussion/Holding_cell") ) {
	return;
	}

$.getScript('https://en.wikipedia.org/w/index.php?title=User:Evad37/XFDcloserCommon.js&action=raw&ctype=text/javascript', function () {
// Make sure [[User:Evad37/XFDcloserCommon.js]] is loaded!

	setSysopStatus();

/* ##### Sandbox usage only (remove when updating main script) ##### */
if ( mw.config.get("wgUserName") === "Evad37" ) {
	isSysop = false;
	console.log("isSysop: " + isSysop);
	TFDpath = "User:Evad37/sandbox/Wikipedia:Templates for discussion/Log/";
}
/* ##### End of sandbox usage only (remove when updating main script) ##### */

	// Add links to actions
	$("h4 > span.mw-headline ").each(function( index ) {
		$(".mw-headline-number", this).prependTo($(this).parent());		// fix for "Auto-number headings" preference
		var template = $(":first-child", this).text();
		if (!template) {							// section header wasn't a link
			template = $(this).text();
			$(this).wrapInner("<span></span>");				// wrap with span so it can be styled later
		}
		var templatee = mw.util.wikiUrlencode(template);			// "pretty"-encoded

		//Check if already closed
		var discussion_element_class = $(this).parent().next().attr("class");
		if ( discussion_element_class ) {					// only closed discussion have element with any class set
			$(this).parent().addClass("boilerplate tfd vfd xfd-closed");	// add classes to enable hiding of closed section headers
		} else {
			var sectionlink = $(this).next().find("a").not(".mw-editsection-visualeditor").attr('href');
			var editsection = sectionlink.split("section=")[1];
			if ( editsection.search("T")<0 ) {				// if true, we're on the subpage
				nom_page = thispage;
			} else {							// if false, section is transcluded from a subpage
				nom_page = sectionlink.split("title=")[1].split("&")[0];
				editsection = editsection.substr(2);			// remove "T-" from section number
			}
			if ( nom_page.includes("Templates_for_discussion/Holding_cell") ) return;

			//Check for collapsed list, and pop out a non-visible copy if found
			//var $collapsedlist = $(this).parent().next().next().find("ul");
			//if ($collapsedlist.length > 0) {
			//	$collapsedlistitems = $collapsedlist.children().clone();
			//	$collapsedlistitems.css( "display", "none" )
			//	$(this).parent().next().append( $collapsedlistitems ).after( "<span style='font-size:85%;padding-left:1em;'>&thinsp;... collapsed list detected (" + $collapsedlistitems.length + " templates)</span>" );
			//}

			//Check if this is a multi-template dicussion
			var $templates = $(this).parent().nextUntil("h4").find("li > span[id].plainlinks.nourlexpansion.1x").filter(":first-child").children("a").filter(":first-child");
console.log("$templates = ");
console.log($templates);
			var templates = new Array($templates.length);
			$templates.each(function( ii ) {
				templates[ii] = $(this).text();
			});
console.log("templates =");
console.log(templates);
			var closing_options;
			if ( templates.length > 1) {
				// This is a multi-discussion
				templates_e = templates.map(function(tname) {
					var te = mw.util.wikiUrlencode(tname).replace(/,/g,"__COMMA__"); //"pretty"-encode, then encode commas encoded as __COMMA__
					return te;
				});
				closing_options = "Closing options: " + 
"<span style='margin-left:5px;'>[<a style='cursor:pointer;' onclick=multi_process_close_tfd('" + templates_e + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "Delete." + "','" + "delete" + "') title='QuickDelete (all)'>qD</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_close_tfd('" + templates_e + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "delete" + "') title='Delete, or other close that will result in the templates being deleted (e.g. Review, Convert, Substitute)'>Delete/other</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_process_close_tfd('" + templates_e + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "Keep." + "','" + "keep" + "') title='QuickKeep (all)'>qK</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_close_tfd('" + templates_e + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "keep" + "') title='Keep, or other close that will result in the template being kept (e.g. Redirect, No Consensus)'>Keep/other</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_close_tfd('" + templates_e + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "other" + "') title='Close requires different actions for one or more of the templates listed (e.g. Merge, Delete some but keep others)'>Other close</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_close_tfd('" + templates_e + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "relist" + "') title='Relist discussion'>Relist</a>]</span>";

			} else if (templates[0] === undefined || !checkNS(template, 10)) {
				// sanity check
				templatee = mw.util.wikiUrlencode($(this).html().replace(/<[^>]*>/g,""));    //this is actually the section header
				closing_options = "No templates detected. <span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_close_tfd('" + templatee + "','" + nom_page + "','" + templatee + "','" + editsection + "','" + "none_close_only" + "') title='Close with comments'>Close</a>]</span>";
			

			} else {
				// not a multi-discussion
				closing_options = "Closing options: " + 
"<span style='margin-left:5px;'>[<a style='cursor:pointer;' onclick=multi_process_close_tfd('" + templatee + "','" + nom_page + "'," + null + ",'" + editsection + "','" + "Delete." + "','" + "delete" + "') title='QuickDelete'>qD</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=close_tfd('" + templatee + "','" + nom_page + "','" + editsection + "','" + "delete" + "') title='Delete, or other close that will result in the template being deleted (e.g. Review, Convert, Substitute)'>Delete/other</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=multi_process_close_tfd('" + templatee + "','" + nom_page + "'," + null + ",'" + editsection + "','" + "Keep." + "','" + "keep" + "') title='QuickKeep'>qK</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=close_tfd('" + templatee + "','" + nom_page + "','" + editsection + "','" + "keep" + "') title='Keep, or other close that will result in the template being kept (e.g. Redirect, No Consensus)'>Keep/other</a>]</span>" + 
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' onclick=close_tfd('" + templatee + "','" + nom_page + "','" + editsection + "','" + "relist" + "') title='Relist discussion'>Relist</a>]</span>";
			}
			$(this).append("<span id=XFDClosing_" + templatee + " style='font-size:85%;margin-left:13px;font-weight:normal;'>" + closing_options + "</span>");
		}
	});
});

});


/* == CLOSING-related functions == */

/* -- Close single-TFD section (prompting for result/commment) -- */
function close_tfd(_templatename, _pagetitle, _sectionnum, _action) {
	var prompt_text;
	if ( _action === "relist" ) {
		prompt_text = "Enter relist comment (optional)";
	} else {
		prompt_text = "Enter result and comment";
	}
	var result_comment = prompt(prompt_text);
	if ( result_comment !== null ) {
		multi_process_close_tfd(_templatename, _pagetitle, null, _sectionnum, result_comment, _action);
	}
}

/* -- Close mulit-TFD section (prompting for result/commment) -- */
//Get comment
function multi_close_tfd(_templatearray, _pagetitle, _sectionheader, _sectionnum, _action) {
	var prompt_text;
	if ( _action === "relist" ) {
		prompt_text = "Enter relist comment (optional)";
	} else {
		prompt_text = "Enter result and comment";
	}
	var result_comment = prompt(prompt_text);
	if ( result_comment !== null ) {
		multi_process_close_tfd(_templatearray, _pagetitle, _sectionheader, _sectionnum, result_comment, _action);
	}
}

/* -- Process the close -- */
function multi_process_close_tfd(templatename, pagetitle, sectionheader, sectionnum, resultcomment, action) {

	var editsum_template_or_section, template_or_null, _anchor, tfd_close_top, tfd_close_bottom, tfd_close_editsum, sig;
	
	// Add REFUND to "soft delete"
	resultcomment = resultcomment.trim().replace(/^soft delete\.?$/gi, "'''soft delete'''. [[WP:REFUND]] applies.");
	
	// Wikitext used for close
	if (sectionheader) {
		editsum_template_or_section = "\"" + sectionheader + "\"";
		template_or_null = null;
		_anchor = sectionheader;
	} else {
		editsum_template_or_section = "for [[:" + templatename + "]]";
		template_or_null = templatename;
		_anchor = templatename;
	}

	deliverMsg( _anchor, "Started closing...", "working" );

	if (isSysop) {
		sig = "~~" + "~~";
	} else {
		sig = "<small>[[Wikipedia:NACD|(non-admin closure)]]</small> ~~" + "~~";
	}

	// Figure out if/where bold markup should be added
	var bolding_info = adjustCommentBolding(resultcomment);
	var bold1 = bolding_info[0];
	var bold2 = bolding_info[1];
	resultcomment = bolding_info[2];
	var rc = bold1 + resultcomment + bold2;
	var editsum_rc = rc.replace(/'''/g, "");
	
	if (action == "relist") {
		//get today's date
		var d = new Date();
		var mmm = getMonthName(d.getUTCMonth());
		todays_subpage = d.getUTCFullYear() + " " + mmm + " " + d.getUTCDate();
		tfd_close_top = "{" + "{subst:tfd top|'''Relisted'''}" + "} on [[" + TFDpath + todays_subpage + "#" + _anchor + "|" + todays_subpage + "]] " + sig;
		tfd_close_bottom = "\n{" + "{subst:tfd bottom}" + "}";
		tfd_close_editsum = "Relisted discussion " + editsum_template_or_section + " on [[" + TFDpath + todays_subpage + "#" + _anchor + "|" + todays_subpage + "]] (using [[User:Evad37/TFDcloser|TFDcloser]])";
	} else {
		tfd_close_top = "{" + "{subst:tfd top|"  + bold1 + resultcomment + bold2 + "}" + "} " + sig;
		tfd_close_bottom = "{" + "{subst:tfd bottom}" + "}";
		tfd_close_editsum = "Closing discussion " + editsum_template_or_section + " as " + editsum_rc + " (using [[User:Evad37/TFDcloser|TFDcloser]])";
	}

	// Get page content and remove {Closing} template if present
	new mw.Api().get( {
			action: 'query',
			titles: pagetitle,
			prop: [ 'revisions', 'info' ],
			rvprop: 'content',
			indexpageids: 1,
			rawcontinue: ''
		} ).done( function( result, jqXHR ) {
			var p_id = result.query.pageids;
			var p_contents = result.query.pages[ p_id ].revisions[ 0 ][ '*' ];
			var sections_array = p_contents.split("====");
			var section_heading = sections_array[((sectionnum-1)*2-1)];
			var section_contents = sections_array[((sectionnum-1)*2)].replace(/{{closing}}/gi, "");
			var updated_section;

			// Add relisted discussions to current day's TFD page
			if (action == "relist") {
				var tfdlinks = section_contents.match(/^\*\s*{{\s*Tfd links\s*\|[^\n]*/gim).join("\n");
				if ( tfdlinks ) {
					updated_section = "====" + section_heading + "====" + "\n" + tfd_close_top + "\n" + tfdlinks + tfd_close_bottom;
				} else {
					updated_section = "====" + section_heading + "====" + "\n" + tfd_close_top + tfd_close_bottom;
				}							
				
				deliverMsg( _anchor, "Adding discussion to today's TFD subpage...", "working" );
				var old_disc = "====" + section_heading + "====" + "\n" + section_contents.replace(/^\n+/,"");
				relist_tfd_disc(template_or_null, old_disc, resultcomment, todays_subpage, sectionheader, _anchor);
				
			} else {
				updated_section = "====" + section_heading + "====" + "\n" + tfd_close_top + section_contents + tfd_close_bottom;
			}

			// Perform edit to close TFD discussion
			new mw.Api().postWithToken( 'edit', {
				action: 'edit',
				title: pagetitle,
				section: sectionnum,
				text: updated_section,
				summary: tfd_close_editsum
			} ).done( function( result, jqXHR ) {

			// If successful, mark as closed & move onto next actions (deletes, or update tfd's if relisted, or do old tfd housekeepings)
				var template_array, i, ii, last_one;
				if (sectionheader) {
					template_array = templatename.split(","); // templatename is a csv string (multiple items)
					for (i = 0; i < template_array.length; i++) {
						template_array[i] = decodeURIComponent(template_array[i]).replace(/__COMMA__/g,","); //unencode commas from __COMMA__
					}
				} else {
					template_array = [decodeURIComponent(templatename)];          // templatename is a string (single item)
				}
				var template_array_length = template_array.length;

				if ( action == "delete" ) {
				//---Delete:---
					markClosed(_anchor, rc);
					deliverMsg( _anchor, "Waiting...", "working" );
					delete_action_prompt(templatename, pagetitle, _anchor);

				} else if ( action == "relist" ) {
				//---Relist:---
					markClosed(_anchor, "Relisted on <a href=//en.wikipedia.org/wiki/" + TFDpath.replace(/\s/gi,"_") + todays_subpage.replace(/\s/gi,"_") + "#" + _anchor +">" + todays_subpage + "</a>", true);	
					deliverMsg( _anchor, "Adding discussion to today's TFD subpage...", "working" );
					for (ii = 0; ii < template_array.length; ii++) {
						if (ii == template_array_length-1) {
							last_one = true;
						} else {
							last_one = false;
						}
						update_template_tfd(template_array[ii], todays_subpage, _anchor, last_one);
					}

				} else if ( action == "none_close_only" ) {
				//---No further action:---
					markClosed(_anchor, rc);
					return;

				} else if ( action == "other" ) {
				//---Other:---
					markClosed(_anchor, rc);
					for (ii = 0; ii < template_array.length; ii++) {
						window.open("//en.wikipedia.org/w/index.php?title=" + template_array[ii] + "&action=edit", _anchor + ii);
					}
					return;

				} else {
				//---Keep:---
					markClosed(_anchor, rc);
					deliverMsg( _anchor, "Updating template description pages...", "working" );
					var rescom = bold1 + resultcomment + bold2;
					var res = rescom.split("'''")[1].trim().replace(/(?:\.|,|;|:)$/, "");
					for (ii = 0; ii < template_array_length; ii++) {
						if (ii == template_array_length-1) {
							last_one = true;
						} else {
							last_one = false;
						}

						make_old_tfd(template_array[ii], res, pagetitle, sectionheader, _anchor, last_one);
					}
				}
			} ).fail( function( code, result ) {
				var error_details = apifailed( code, result );
				deliverMsg( _anchor, "Could not close discussion " + error_details, "error" );
			} );

	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( _anchor, "Could not read contents of page " + pagetitle + "; could not close discussion " + error_details, "error" );
	} );
}


/* == DELETE-relatated functions == */

/* -- Prompt -- */
function delete_action_prompt(template, TFD_page, anchor) {

	var log_date = TFD_page.match(/\d{4}_\w*_\d{1,2}/)[0];

	var holdingcellbuttons = "<span id='hc_sections'><button onclick=addToHoldingCell('" + template + "',2,'" + anchor + "','" + log_date + "')>Review</button> <button onclick=holdCellMergeSections('" + template + "','" + anchor + "','" + log_date + "')>Merge</button> <button onclick=addToHoldingCell('" + template + "',11,'" + anchor + "','" + log_date + "')>Convert</button> <button onclick=addToHoldingCell('" + template + "',12,'" + anchor + "','" + log_date + "')>Substitute</button> <button onclick=addToHoldingCell('" + template + "',13,'" + anchor + "','" + log_date + "')>Orphan</button> <button onclick=addToHoldingCell('" + template + "',14,'" + anchor + "','" + log_date + "')>Ready for deletion</button></span>";

	var prompt_msg;
	if (isSysop) {
		var delReason = "["+"["+TFD_page+"#"+anchor+"]"+"]";
		prompt_msg = "<button onclick=deleteNow('" + template + "','" + delReason + "','" + anchor + "')>Delete Now</button> or choose holding cell section: " + holdingcellbuttons;
	} else {
		prompt_msg = "Choose holding cell section: " + holdingcellbuttons;
	}

	deliverMsg( anchor, prompt_msg, "question");
}

function holdCellMergeSections(template, anchor, log_date) {
	var mergebuttons = "Choose 'Merge' subsection: <button onclick=addToHoldingCell('" + template + "',4,'" + anchor + "','" + log_date + "')>Arts</button> <button onclick=addToHoldingCell('" + template + "',5,'" + anchor + "','" + log_date + "')>Geography, politics and governance</button> <button onclick=addToHoldingCell('" + template + "',6,'" + anchor + "','" + log_date + "')>Religion</button> <button onclick=addToHoldingCell('" + template + "',7,'" + anchor + "','" + log_date + "')>Sports</button> <button onclick=addToHoldingCell('" + template + "',8,'" + anchor + "','" + log_date + "')>Transport</button> <button onclick=addToHoldingCell('" + template + "',9,'" + anchor + "','" + log_date + "')>Other</button> <button onclick=addToHoldingCell('" + template + "',10,'" + anchor + "','" + log_date + "')>Meta</button>";
	deliverMsg( anchor, mergebuttons, "question", true);
}


/* -- Perform delete action -- */
function deleteNow(template_string, thereason, anchor) {

	var ii, isLast;

	deliverMsg( anchor, null, null, true);				// clears prompt buttons
	deliverMsg( anchor, "Deleting...", "working", true );		// clears waiting messages

	if ( template_string.includes(",Template:") ) {			// template_string is a csv string (multiple items)
		template_array = template_string.split(",");
		for (i = 0; i < template_array.length; i++) {
			template_array[i] = decodeURIComponent(template_array[i]).replace(/__COMMA__/g,","); //unencode commas from __COMMA__
		}
	} else {							// template_string is a string (single item)
		template_array = [decodeURIComponent(template_string)];
	}

	for (ii = 0; ii < template_array.length; ii++) {
		if (ii == template_array.length-1) {
			isLast = true;
		} else {
			isLast = false;
		}		
	
		if ( !checkNS(template_array[ii], 10) ) {
			deliverMsg( anchor, "\"" + template_array[ii] + "\" is not in Template: namespace, TFDcloser will not delete this page", "error", isLast, null, !isLast);
			return;
		}
		perform_delete(template_array[ii], thereason, anchor, isLast);
	}
}

function perform_delete(template, del_reason, _anchor, _isLast){
	new mw.Api().postWithToken( 'delete', {
		action: 'delete',
		title: template,
		reason: del_reason,
	} ).done( function( result, jqXHR ) {
		deliverMsg( _anchor, "Deleted " + template, "deleted", null, null, true );
		if (_isLast) {
			deliverMsg( _anchor, null, null, true ); // remove "Deleting..." message
		}
	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( _anchor, "Could not delete " + template + " " + error_details, "warning", null, null, true );
		if (_isLast) {
			deliverMsg( _anchor, null, null, true ); //remove "Deleting..." message
		}
	} );
}

/* -- Holding cell -- */
function addToHoldingCell(template_string, holdCellSection, anchor, log_date) {

	var i, isLast, delete_param, tag_speedy, section_param, hc_editsum, last_one;


	deliverMsg( anchor, null, null, true);					// clears prompt buttons
	deliverMsg( anchor, "Listing at holding cell...", "working", true );	// clears waiting message

	 //Build up wikitext for edit

	if ( holdCellSection === 14 ) {						// 14 is "Ready for deletion"
		delete_param = "|delete=1";
		tag_speedy = true;
	} else {
		delete_param = "";
		tag_speedy = false;
	}
	if ( template_string === anchor ) {
		section_param = "";
	} else {
		section_param = "|section=" + anchor;
	}
	var wikitext_append = "";
	if ( template_string.includes(",Template:") ) {				// template_string is a csv string (multiple items)
		template_array = template_string.split(",");
		for (i = 0; i < template_array.length; i++) {
			if (i === template_array.length-1) {
				last_one = true;
			} else {
				last_one = false;
			}
			template_array[i] = decodeURIComponent(template_array[i]).replace(/__COMMA__/g,",");
			addBeingDeleted(template_array[i], anchor, log_date, last_one, tag_speedy);
			wikitext_append = wikitext_append + "*{" + "{tfdl|" + template_array[i].replace(/_/g," ").slice(9) + "|" + log_date.replace(/_/g," ") + section_param + delete_param + "}}\n";
			hc_editsum = "Listing templates per [[" + TFDpath + log_date + "#" + anchor + "]] (using [[User:Evad37/TFDcloser|TFDcloser]])";
		}
	} else {								// template_string is a string (single item)
		addBeingDeleted(decodeURIComponent(template_string), anchor, log_date, true, tag_speedy);
		wikitext_append = "*{" + "{tfdl|" + decodeURIComponent(template_string).replace(/_/g," ").slice(9) + "|" + log_date.replace(/_/g," ") + section_param + delete_param + "}}\n";
		hc_editsum = "Listing [[" + decodeURIComponent(template_string) + "]] per [[" + TFDpath + log_date + "#" + anchor + "]] (using [[User:Evad37/TFDcloser|TFDcloser]])";
	}

	 // ... make api call to append wikitext to the section ...
	var holdingcellpagetitle = TFDpath.slice(0,-4) + "Holding cell";
	new mw.Api().get( {
		action: 'query',
		titles: holdingcellpagetitle,
		prop: [ 'revisions', 'info' ],
		rvprop: 'content',
		indexpageids: 1,
		rawcontinue: ''
	} ).done( function( result, jqXHR ) {
		var p_id = result.query.pageids;
		var p_contents = result.query.pages[ p_id ].revisions[ 0 ][ '*' ].replace(/====/gi, "==="); //make all headings level 3 so sections can be counted
		var sections_array = p_contents.split("===");
		var section_heading = sections_array[(holdCellSection*2-1)];
		var section_contents = sections_array[(holdCellSection*2)];
		 //remove "* ''None currently''" if after end of, or before beginning of, <!--html comment-->
		section_contents = section_contents.replace(/-->\n*\*\s*''None currently''/gi, "-->").replace(/\*\s*''None currently''\n*<!--/gi, "<!--");
		var heading_level;
		if ( (4 <= holdCellSection) && ( holdCellSection <= 10) ) {			//Merge subsections
			heading_level = "====";
		} else {
			heading_level = "===";
		}
		var updated_section = heading_level + section_heading + heading_level + "\n" + section_contents.trim() + "\n" + wikitext_append;

		new mw.Api().postWithToken( 'edit', {
			action: 'edit',
			title: holdingcellpagetitle,
			section: holdCellSection,
			text: updated_section,
			summary: hc_editsum
		} ).done( function( result, jqXHR ) {
			deliverMsg( anchor, "Listed at holding cell", "is_done", null, null, true );
		} ).fail( function( code, result ) {
			var error_details = apifailed( code, result );
			deliverMsg( anchor, "Could not edit holding cell " + error_details, "error", null, null, true);
		} );

	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( _anchor, "Could not read contents of page " + holdingcellpagetitle + "; could not add templates to holding cell " + error_details, "error", null, null, true);
	} );
	
}

/* -- Add Being deleted (or Db-xfd) template -- */
function addBeingDeleted(template, anchor, log_date, last, speedy) {

	if ( !checkNS(template, 10) ) {
		deliverMsg( anchor, "\"" + template + "\" is not in Template: namespace, TFDcloser will not edit this page", "error", last, null, !last);
		return;
	}

	var updated_content, uc_template, uc_template_name, uc_editsum;
	if ( speedy ) {
		uc_template_name = "Db-xfd";
		uc_editsum = "[[WP:G6|G6]] Speedy deletion nomination, per close at [[" + TFDpath + log_date + "#" + anchor + "]]";
		uc_template = "{" + "{db-xfd|votepage=/Log/" + log_date + "#" + anchor + "}" + "}";
	} else {
		uc_template_name = "Being deleted";
		uc_editsum = "Per close at [[" + TFDpath + log_date + "#" + anchor + "]], added {" + "{being deleted}" + "} (using [[User:Evad37/TFDcloser|TFDcloser]])";
		uc_template = "{" + "{Being deleted|" + log_date + "|" + anchor + "}" + "}";
	}

	//replace {Template for discussion/dated} or {Tfm/dated} (which may or may not be noincluded) with noincluded {Being deleted}
	new mw.Api().get( {
		action: 'query',
		titles: template,
		prop: [ 'revisions', 'info' ],
		rvprop: 'content',
		indexpageids: 1,
		rawcontinue: ''
	} ).done( function( result, jqXHR ) {
		var t_id = result.query.pageids;
		var t_contents = result.query.pages[ t_id ].revisions[ 0 ][ '*' ];
		if ( t_contents.search(/{{(Template for discussion|Tfm)\/dated[^}}]*}{2,4}/gi) < 0 ) {
			updated_content = "<no" + "include>" + uc_template + "</no" + "include>" + t_contents;
		} else {
			updated_content = t_contents.replace(/(?:<noinclude>[\n\s]*)*{{(Template for discussion|Tfm)\/dated[^}}]*}{2,4}(?:[\n\s]*<\/noinclude>)*/gi, "<no" + "include>" + uc_template + "</no" + "include>");
		}

		//Perform edit
		new mw.Api().postWithToken( 'edit', {
			action: 'edit',
			title: template,
			text: updated_content,
			summary: uc_editsum
		} ).done( function( result, jqXHR ) {
			deliverMsg(anchor, "{" + "{" + uc_template_name + "}" + "} added to " + template, "is_done", last, null, !last);
		} ).fail( function( code, result ) {
			var error_details = apifailed( code, result );
			deliverMsg(anchor, "Could not add {" + "{" + uc_template_name + "}" + "} to " + template + " " + error_details, "error", last, null, !last);
		} );

	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( anchor, template + " not found; could not add {" + "{" + uc_template_name + "}" + "} " + error_details, "warning", last, null, !last);
	} );

}


/* == KEEP-relatated functions == */

function make_old_tfd(templatename, resultcomment, tfdpage, sectionheader, anchor, last) {

	var disc_param, nomdate, templatetalkpage, oldtfd_wikitext;

	if ( !checkNS(templatename, 10) ) {
		deliverMsg( anchor, "\"" + templatename + "\" is not in Template: namespace, TFDcloser will not edit this page or its talk page", "error", lasttemplate, null, !lasttemplate);
		return;
	}

	if (sectionheader) {
		disc_param = "|disc=" + sectionheader;
	} else {
		disc_param = "";
	}

	nomdate = tfdpage.split(TFDpath.replace(/\s/gi,"_"))[1].replace(/_/gi," ");           //unencode spaces from _
	templatetalkpage = templatename.replace("Template", "Template_talk");
	oldtfd_wikitext = "{" + "{oldtfdfull|date=" + nomdate + "|result=" + resultcomment + disc_param + " }" + "}\n";

	new mw.Api().postWithToken( 'edit', {
		action: 'edit',
		title: templatetalkpage,
		prependtext: oldtfd_wikitext,
		summary: "Old TFD – " + nomdate + ": " + resultcomment + " (using [[User:Evad37/TFDcloser|TFDcloser]])"
	} ).done( function( result, jqXHR ) {
		deliverMsg( anchor, "Updated " + templatetalkpage, "is_done", null, null, true );

		//Get template description page, remove tfd template
		new mw.Api().get( {
			action: 'query',
			titles: templatename,
			prop: [ 'revisions', 'info' ],
			rvprop: 'content',
			indexpageids: 1,
			rawcontinue: ''
		} ).done( function( result, jqXHR ) {
			var t_id = result.query.pageids;
			var t_contents = result.query.pages[ t_id ].revisions[ 0 ][ '*' ];
			var updated_template_content = t_contents.replace(/(?:<noinclude>[\n\s]*)*{{(Template for discussion|Tfm)\/dated[^}}]*}{2,4}(?:[\n\s]*<\/noinclude>)*/gi, "");

				//Perform edit to remove tfd template
				new mw.Api().postWithToken( 'edit', {
					action: 'edit',
					title: templatename,
					text: updated_template_content,
					summary: "TFD closed as " + resultcomment + " (using [[User:Evad37/TFDcloser|TFDcloser]])"
				} ).done( function( result, jqXHR ) {
					deliverMsg( anchor, "Removed {{Template for discussion/dated}} (or {{Tfm/dated}}) from " + templatename, "is_done", last, null, !last);
				} ).fail( function( code, result ) {
					var error_details = apifailed( code, result );
					deliverMsg( anchor, "Could not remove {{Template for discussion/dated}} (or {{Tfm/dated}}) from " + templatename + " " + error_details, "warning", last, null, !last);
				} );

		} ).fail( function( code, result ) {
			var error_details = apifailed( code, result );
			deliverMsg( anchor, templatename + " not found; could not remove {{Template for discussion/dated}} (or {{Tfm/dated}}) " + error_details, "warning", last, null, !last);
		} );

	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( anchor, "Could not edit " + templatetalkpage + " " + error_details, "warning", last, null, !last);
	} );

}


/* == RELIST-related functions == */

/* -- Relist discussion on current day's TFD subpage -- */
function relist_tfd_disc(templatename, discussion, relistcomment, todaysdate, sectionheader, anchor) {

	var relist_editsum, relists, num_relists, rc_if_any, newdiscussion;

	//Edit summary varies based on if sectionheader is defined or not
	if ( sectionheader ) {
		relist_editsum = "Relisting \"" + sectionheader + "\" (using [[User:Evad37/TFDcloser|TFDcloser]])";
	} else {
		relist_editsum = "Relisting [[:" + templatename + "]] (using [[User:Evad37/TFDcloser|TFDcloser]])";
	}

	//Check for number of relists, append {relist} template
	relists = discussion.match("[[Wikipedia:Deletion process#Relisting discussions|Relisted]]");
	if ( relists ) {
		num_relists = relists.length + 1;
	} else {
		num_relists = 1;
	}
	if ( relistcomment !== "" ) {
		rc_if_any = relistcomment;
	} else {
		rc_if_any = "";
	}
	newdiscussion = discussion.trim() + "\n{" + "{subst:Relist|" + rc_if_any + "|" + num_relists + "}}\n";

	//Check if any discussion already listed 
	new mw.Api().get( {
		action: 'query',
		titles: TFDpath + todaysdate,
		prop: [ 'revisions', 'info' ],
		rvprop: 'content',
		indexpageids: 1,
		rawcontinue: ''
	} ).done( function( result, jqXHR ) {
		var _id = result.query.pageids;
		var _contents = result.query.pages[ _id ].revisions[ 0 ][ '*' ];
		var _h4 = _contents.match("====");
		if ( _h4 ) {							// there is at least 1 level 4 heading on page - can prepend to section #2
			new mw.Api().postWithToken( 'edit', {
				action: 'edit',
				title: TFDpath + todaysdate,
				section: 2,
				prependtext: newdiscussion,
				summary: relist_editsum
			} ).done( function( result, jqXHR ) {
				deliverMsg( anchor, null, null, true );		// remove working message
				window.open("//en.wikipedia.org/wiki/" + TFDpath.replace(/\s/gi,"_") + todaysdate.replace(/\s/gi,"_"), "tfdtoday");
			} ).fail( function( code, result ) {
				var error_details = apifailed( code, result );
				deliverMsg( anchor, "Could not relist discussion "  + error_details, "error", true);

			} );
		} else {							// there are no level 4 headings on page - can append to section #1
			new mw.Api().postWithToken( 'edit', {
				action: 'edit',
				title: TFDpath + todaysdate,
				section: 1,
				appendtext: "\n" + newdiscussion,
				summary: relist_editsum
			} ).done( function( result, jqXHR ) {
				deliverMsg( anchor, null, null, true );		// remove working message
				window.open("//en.wikipedia.org/wiki/" + TFDpath.replace(/\s/gi,"_") + todaysdate.replace(/\s/gi,"_"), "tfdtoday");
			} ).fail( function( code, result ) {
				var error_details = apifailed( code, result );
				deliverMsg( anchor, "Could not relist discussion " + error_details, "error", true );
			} );
		}
	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( anchor, TFDpath + todaysdate + " not found; could not relist discussion " + error_details, "error", true );
	} );
}


/* -- Update template tfd template (after relisting) -- */
function update_template_tfd(templatename, today_subpage, anchor, lasttemplate) {
	if ( !checkNS(templatename, 10) ) {
		deliverMsg( anchor, "\"" + templatename + "\" is not in Template: namespace, TFDcloser will not edit this page", "error", lasttemplate, null, !lasttemplate);
		return;
	}
	new mw.Api().get( {
		action: 'query',
		titles: templatename,
		prop: [ 'revisions', 'info' ],
		rvprop: 'content',
		indexpageids: 1,
		rawcontinue: ''
	} ).done( function( result, jqXHR ) {
		var template_id = result.query.pageids;
		var template_contents = result.query.pages[ template_id ].revisions[ 0 ][ '*' ];
		var new_template_contents = template_contents.replace(/Wikipedia:Templates(_|\s){1}for(_|\s){1}discussion\/Log\/\d{4}(_|\s){1}\w*(_|\s){1}\d{1,2}#(?=[^}]*}{2})/gi, "Wikipedia:Templates for discussion/Log/" + today_subpage + "#" );
		new mw.Api().postWithToken( 'edit', {
			action: 'edit',
			title: templatename,
			text: new_template_contents,
			summary: "Updating {{tfd}} template: template was relisted (using [[User:Evad37/TFDcloser|TFDcloser]])"
			} ).done( function( result, jqXHR ) {
				deliverMsg( anchor, "Updated {{Template for discussion/dated}} (or {{Tfm/dated}}) on " + templatename, "is_done", lasttemplate, null, !lasttemplate);
			} ).fail( function( code, result ) {
				var error_details = apifailed( code, result );
				deliverMsg( anchor, "Could not update {{Template for discussion/dated}} (or {{Tfm/dated}}) on " + templatename + " " + error_details, "warning", lasttemplate, null, !lasttemplate);
			} );
	} ).fail( function( code, result ) {
		var error_details = apifailed( code, result );
		deliverMsg( anchor, templatename + " not found; could not update {{Template for discussion/dated}} (or {{Tfm/dated}}) " + error_details, "warning", lasttemplate, null, !lasttemplate);
	} );

}
// </nowiki>