User:Davey2010/xfdcloser2.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*******************************************************************************
XFDcloser --- by Evad37
> A script that assists in closing AFD, CFD, FFD, MFD, RFD, and TFD discussions
--------------------------------------------------------------------------------
* IMPORTANT NOTE:
You are responsible for any edits/actions performed using XFDcloser! Please
make sure you understand relevant Wikipedia policies and procedures, and use
this tool accordingly.
(Some pertinent pages are: [[WP:CON]], [[WP:CLOSE]], [[WP:NAC]])
--------------------------------------------------------------------------------
* Version: 2.17 (see page history for full change log)
* Release notes:
- Remove newline after Tfd nomination template, if present
- There may occasionally be bugs encountered, please check contributions
and deletion actions carefully and report any problems
--------------------------------------------------------------------------------
* See [[User:Evad37/XFDcloser]] for installation details and documentation
--------------------------------------------------------------------------------
* Licencing note: Originally published on the English Wikipedia at
https://en.wikipedia.org/wiki/User:Evad37/XFDcloser.js ( and/or
https://en.wikipedia.org/wiki/User:Evad37/XFDcloser/sandbox.js )
and available under Creative Commons Attribution-ShareAlike 3.0 Unported
License (CC BY-SA 3.0) https://creativecommons.org/licenses/by-sa/3.0/
* Attribution note: This script incorporates code derived from, and is a direct
replacement for, these other scripts also written by Evad37:
- https://en.wikipedia.org/wiki/User:Evad37/CFDcloser.js
- https://en.wikipedia.org/wiki/User:Evad37/FFDcloser.js
- https://en.wikipedia.org/wiki/User:Evad37/TFDcloser.js
Futhermore, it incorporates code copied/derived from:
- https://en.wikipedia.org/wiki/User:Mr.Z-man/closeAFD2.js
- https://en.wikipedia.org/wiki/MediaWiki:Gadget-twinkleunlink.js
- https://en.wikipedia.org/wiki/MediaWiki:Gadget-morebits.js
Further notes:
- See the "History" pages for these pages' authors.
- All of the these pages are also published on Wikipedia, and thus
also available under the CC BY-SA 3.0 licence.
- The following box is a reproduction of the copyright and permission notices
from https://en.wikipedia.org/wiki/User:Mr.Z-man/closeAFD2.js :
_ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ _
| |
| Copyright (c) 2013 Mr.Z-man |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal|
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,|
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| THE SOFTWARE. |
|_ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ _|
--------------------------------------------------------------------------------
Have fun, and happy editing! - Evad37
*******************************************************************************/
/* <nowiki> */
mw.loader.using( ['mediawiki.util', 'mediawiki.api', 'mediawiki.Title', 'mediawiki.RegExp',
'oojs-ui-core', 'oojs-ui-windows', 'jquery.ui.dialog'], function () {
// Load Morebits if not already available
if ( window.Morebits == null ) {
importScript('MediaWiki:Gadget-morebits.js');
importStylesheet( 'MediaWiki:Gadget-morebits.css' );
}
$( function($) {
/* == Basic settings and checks == */
/* ******************************* */
/* --- Quick checks that script should be running (then it's safe to define vars and function) --- */
//Check 1: Page is not in edit/history/diff/oldid mode
var thispageurl = window.location.href;
if (thispageurl.indexOf("?") !== -1) {
console.log("[XFDcloser] Page is in edit, history, diff, or oldid mode");
return;
}
//Check 2: User is ExtendedConfirmed and/or Sysop
if ( -1 === $.inArray('extendedconfirmed', mw.config.get('wgUserGroups')) && -1 === $.inArray('sysop', mw.config.get('wgUserGroups')) ) {
console.log("[XFDcloser] User is not extendedconfirmed or sysop");
return;
}
//Check 3: Page is an XfD page
var thispage = mw.config.get( 'wgPageName' );
var xfdpage_regex = /(Articles_for_deletion\/|Miscellany_for_deletion|User:Cyberbot_I\/AfD's_requiring_attention|Wikipedia:WikiProject_Deletion_sorting\/(?!(Flat|Compact)$)|(Categories|Files|Templates|Redirects)_for_discussion(?!\/(Working|Holding_cell)))(?!\/?Administrator_instructions$)/;
if ( thispage.search(xfdpage_regex) === -1 ) {
console.log("[XFDcloser] Current page is not an XfD page");
return;
}
//xfdSetting object holds process-specific setting
//FORLATER: consider making 'xfdSetting' object via constructor
var xfdSetting = {};
xfdSetting.html = {};
xfdSetting.wikitext = {};
xfdSetting.regex = {};
xfdSetting.fn = {};
xfdSetting.transcludedOnly = false;
/* --- Load appropriate settings --- */
if ( thispage.includes("Wikipedia:Miscellany_for_deletion") ) {
//MFD
xfdSetting.xfd_type = "mfd";
xfdSetting.html.head = "h4";
xfdSetting.html.list = "dl";
xfdSetting.html.listitem = "dd";
xfdSetting.path = "Wikipedia:Miscellany for deletion";
xfdSetting.subpagePath = "Wikipedia:Miscellany for deletion/";
xfdSetting.ns_number = -5; //not an actual ns number, just used here to indicate all subject-spaces
xfdSetting.wikitext.closeTop = "{" + "{subst:Mfd top|'''__RESULT__'''}" + "}__TO_TARGET__. __RATIONALE__ __SIG__";
xfdSetting.wikitext.closeBottom = "{" +"{subst:Mfd bottom}" + "}";
xfdSetting.wikitext.oldXfd = "{{Old MfD |date=__DATE__ |result='''__RESULT__''' |page=__SUBPAGE__}}\n";
xfdSetting.wikitext.mergeFrom = "{" + "{mfd-mergefrom|__NOMINATED__|__DEBATE__|__DATE__}" + "}\n";
xfdSetting.wikitext.mergeTo = "{" + "{mfd-mergeto|__TARGET__|__DEBATE__|__DATE__|__TARGETTALK__}" + "}\n";
xfdSetting.wikitext.alreadyClosed = "{{#ifeq:{{FULLPAGENAME}}|Wikipedia:Miscellany for deletion|{{collapse bottom}}|}}";
xfdSetting.regex.nomTemplate = /(?:<noinclude>\s*)?(?:{{mfd[^}}]*}}|<span id="mfd".*?<\/span> \[\[Category:Miscellaneous pages for deletion\|?.*\]\]\s*)(?:\s*<\/noinclude>)?/gi;
xfdSetting.fn.sectionCalc = function() { //TODO: check this
return 2;
};
} else if ( thispage.includes("Categories_for_discussion/") ) {
//CFD
xfdSetting.xfd_type = "cfd";
xfdSetting.html.head = "h4";
xfdSetting.html.list = "ul";
xfdSetting.html.listitem = "li";
xfdSetting.html.nthSpan = "2";
xfdSetting.path = "Wikipedia:Categories for discussion/Log/";
xfdSetting.ns_number = 14;
xfdSetting.wikitext.closeTop = "{" + "{subst:cfd top}" + "} '''__RESULT__'''__TO_TARGET____RPUNCT__ __RATIONALE__ __SIG__";
xfdSetting.wikitext.closeBottom = "{" +"{subst:cfd bottom}" + "}";
xfdSetting.wikitext.oldXfd = "{" + "{Old CfD |__SECTION__ |date=__DATE__ |action=__ACTION__ |result=__RESULT__}" + "}";
xfdSetting.wikitext.alreadyClosed = "<!-- Template:Cfd top -->";
xfdSetting.fn.sectionCalc = function(section_number) {
return (section_number-1)*2;
};
} else if ( thispage.includes("Files_for_discussion") ) {
//FFD
xfdSetting.xfd_type = "ffd";
xfdSetting.html.head = "h4";
xfdSetting.html.list = "dl";
xfdSetting.html.listitem = "dd";
xfdSetting.html.nthSpan = "1";
xfdSetting.path = "Wikipedia:Files for discussion/";
xfdSetting.ns_number = 6;
xfdSetting.wikitext.closeTop = "{" + "{subst:ffd top|'''__RESULT__'''}" + "}__TO_TARGET____RPUNCT__ __RATIONALE__ __SIG__";
xfdSetting.wikitext.closeBottom = "{" +"{subst:ffd bottom}" + "}";
xfdSetting.wikitext.oldXfd = "{" + "{oldffdfull |date=__DATE__ |result='''__RESULT__''' |page=__SECTION__}" + "}\n";
xfdSetting.wikitext.pagelinks = "{" + "{subst:ffd2|__PAGE__|multi=yes}" + "}\n";
xfdSetting.regex.nomTemplate = /{{ffd[^}}]*}}/gi;
xfdSetting.regex.relistPattern = /{{\s*ffd\s*\|\s*log\s*=\s*[^|}}]*/gi;
xfdSetting.wikitext.relistReplace = "{{ffd|log=__TODAY__";
xfdSetting.wikitext.alreadyClosed = "<!--Template:Ffd top-->";
xfdSetting.fn.sectionCalc = function(section_number) {
return (section_number-1)*2;
};
} else if ( thispage.includes("Templates_for_discussion") ) {
//TFD
xfdSetting.xfd_type = "tfd";
xfdSetting.html.head = "h4";
xfdSetting.html.list = "ul";
xfdSetting.html.listitem = "li";
xfdSetting.html.nthSpan = "1";
xfdSetting.path = "Wikipedia:Templates for discussion/Log/";
xfdSetting.ns_number = 10;
xfdSetting.wikitext.closeTop = "{" + "{subst:Tfd top|'''__RESULT__'''}" + "}__TO_TARGET____RPUNCT__ __RATIONALE__ __SIG__";
xfdSetting.wikitext.closeBottom = "{" +"{subst:Tfd bottom}" + "}";
xfdSetting.wikitext.oldXfd = "{" + "{oldtfdfull|date= __DATE__ |result=__RESULT__ |disc=__SECTION__}" + "}\n";
xfdSetting.wikitext.pagelinks = "* {" + "{tfd links|__PAGE__}" + "}\n";
xfdSetting.regex.nomTemplate = /(?:<noinclude>[\n\s]*)?{{(?:Template for discussion|Tfm)\/dated[^{}]*(?:{{[^}}]*}}[^}}]*)*?}}(?:[\n\s]*<\/noinclude>)?(\n)?/gi;
xfdSetting.regex.relistPattern = /Wikipedia:Templates(_|\s){1}for(_|\s){1}discussion\/Log\/\d{4}(_|\s){1}\w*(_|\s){1}\d{1,2}#(?=[^}]*}{2})/gi;
xfdSetting.wikitext.relistReplace = "Wikipedia:Templates for discussion/Log/__TODAY__#";
xfdSetting.wikitext.alreadyClosed = "<!-- Tfd top -->";
xfdSetting.fn.sectionCalc = function(section_number) {
return (section_number-1)*2;
};
} else if ( thispage.includes("Redirects_for_discussion") ) {
//RFD
xfdSetting.xfd_type = "rfd";
xfdSetting.html.head = "h4";
xfdSetting.html.list = "ul";
xfdSetting.html.listitem = "li";
xfdSetting.path = "Wikipedia:Redirects for discussion/Log/";
xfdSetting.ns_number = -5; //not an actual ns number, just used here to indicate all subject-spaces
xfdSetting.wikitext.closeTop = "{{subst:Rfd top|'''__RESULT__'''}}__TO_TARGET____RPUNCT__ __RATIONALE__ __SIG__";
xfdSetting.wikitext.closeBottom = "{{subst:Rfd bottom}}";
xfdSetting.wikitext.oldXfd = "{{Old RfD |date={{subst:date|__FIRSTDATE__}} |result='''__RESULT__''' |page=__DATE__#__SECTION__}}\n";
xfdSetting.wikitext.alreadyClosed = "<!-- Template:Rfd top-->";
xfdSetting.regex.nomTemplate = /(^{{.*#invoke:RfD(?:.|\n)*?-->\|content=\n?|\n?<!-- Don't add anything after this line. -->\n}})/g;
xfdSetting.fn.sectionCalc = function(section_number) {
return (section_number-1)*2;
};
} else if ( thispage.search(/(Articles_for_deletion|User:Cyberbot_I|Wikipedia:WikiProject_Deletion_sorting)/) !== -1 ) {
//AFD
xfdSetting.xfd_type = "afd";
xfdSetting.html.head = "h3";
xfdSetting.html.list = "dl";
xfdSetting.html.listitem = "dd";
xfdSetting.html.nthSpan = "2";
xfdSetting.path = "Wikipedia:Articles for deletion/Log/";
xfdSetting.subpagePath = "Wikipedia:Articles for deletion/";
xfdSetting.ns_number = 0;
xfdSetting.wikitext.closeTop = "{" + "{subst:Afd top|'''__RESULT__'''}" + "}__TO_TARGET____RPUNCT__ __RATIONALE__ __SIG__";
xfdSetting.wikitext.closeBottom = "{" +"{subst:Afd bottom}" + "}";
xfdSetting.wikitext.mergeFrom = "{" + "{Afd-merge from|__NOMINATED__|__DEBATE__|__DATE__}" + "}\n";
xfdSetting.wikitext.mergeTo = "{" + "{Afd-merge to|__TARGET__|__DEBATE__|__DATE__}" + "}\n";
xfdSetting.wikitext.alreadyClosed = "<!--Template:Afd bottom-->";
xfdSetting.regex.nomTemplate = /(?:{{[Aa]rticle for deletion\/dated|<!-- Please do not remove or change this AfD message)(?:.|\n)*?}}(?:(?:.|\n)+this\ point -->)?\s*/g;
xfdSetting.fn.sectionCalc = function() {
return 2;
};
if ( thispage.search(/(User:Cyberbot_I|Wikipedia:WikiProject_Deletion_sorting)/) !== -1 ) {
xfdSetting.transcludedOnly = true;
}
} else {
return;
}
/* --- Common vars --- */
//Vars to be avaialbale for all subfunctions are stored in the xfdc object
var xfdc = {};
xfdc.script_advert = " ([[WP:XFDC|XFDcloser]])";
xfdc.tasks_completed = {};
xfdc.tasks_to_do = {};
xfdc.task_errors = {};
xfdc.monthnames = [ // array needed to convert zero-indexed month number from getUTCMonth()
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
xfdc.namespaces = mw.config.get('wgFormattedNamespaces');
xfdc.namespaces["0"] = "article"; // is blank by default
xfdc.namespaces["-5"] = "(any) non-talk"; //not an actual namespace, used here all for subject namespaces
xfdc.namespaces["-4"] = "(any) talk"; //not an actual namespace, used here all for talk namespaces
xfdc.unlink_ns = ["0", "10", "100", "118"]; //main, template, portal, draft
xfdc.eins = 4; //Wikipedia:
// Set sysop status
xfdc.isSysop = false;
xfdc.sig = sig = "<small>[[Wikipedia:NACD|(non-admin closure)]]</small> ~~" + "~~";
if ( -1 !== $.inArray( 'sysop', mw.config.get( 'wgUserGroups' ) ) ) {
xfdc.isSysop = true;
xfdc.sig = "~~" + "~~";
}
//Keep track of how many closes/relists have been started and completed
xfdc.started = 0;
xfdc.finished = 0;
//Warn if unloading before closes/relists are completed
$(window).on("beforeunload", function(e) {
if ( xfdc.started > xfdc.finished ) {
e.returnValue = "";
return "";
}
});
//Keep track of afd logpage edits using deferred objects, to know when it is safe to read the wikitext
xfdc.afdLogEdit = [$.Deferred().resolve()];
/* === Common functions === */
// Subfunctions are stored in XFDcloser object
var XFDcloser = {};
/* -- Misc. functions -- */
//Object manipulation
XFDcloser.val2key = function(val, obj) {
for ( var k in obj ) {
if ( obj[k] === val ) {
return k;
}
}
};
//Make a link in HTML
XFDcloser.makeLink = function(linktarget, linktext) {
if ( linktext == null ) {
linktext = linktarget;
}
return '<a href="https://en.wikipedia.org/wiki/' +
mw.util.wikiUrlencode(linktarget) + '" target="_blank">' + linktext + '</a>';
};
//Make api error details message
XFDcloser.makeApiErrorMsg = function(code, jqxhr) {
var $details = $("<span>").css("font-size", "90%").text("– Details: ");
var $italics = $("<span>").css("font-style", "italic").appendTo($details);
if ( code === "http" && jqxhr.textStatus === "error" ) {
$italics.text("HTTP error " + jqxhr.xhr.status);
} else if ( code === "http" ) {
$italics.text("HTTP error: " + jqxhr.textStatus);
} else if ( code === "ok-but-empty" ) {
$italics.text("Got an empty response from the server");
} else {
$italics.text("API error: " + code);
}
return $details;
};
/* multiButtonConfirm - uses OOjs UI to create a multi-button confirm dialogue
* Parameters:
* title {string} - title for the dialogue
* message {string} - message for the dialogue. HTML tags are escaped, newline characters are ignored.
* buttons {array} - array of objects which each represent a buttons to show at the bottom of the prompt.
* Each object can have the following keys:
* "label" : {string} - label to show on the button
* "action": {string|null} - return value if that button is selected by user
* "flags" : {string|null} - "safe", "primary", "progressive", or "destructive"
* per https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
* callback {function} - callback function for after a button is selected (passed that button's "action" value)
* options {object} - key/value pairs where the key is an option and the value is a boolean.
* Available options are:
* "verbose" : {true|false} - format as a verbose message (left- instead of center-aligned)
* "unescape": {true|false} - unescape the following simple HTML tags (no attributes) in the
* message: <br>, <p>, <ul>, <li> (and closing tags or self-closed tags)
*/
XFDcloser.multiButtonConfirm = function(title, message, buttons, callback, options) {
var messageDialog = new OO.ui.MessageDialog();
var windowManager = new OO.ui.WindowManager();
$( 'body' ).append( windowManager.$element );
windowManager.addWindows( [ messageDialog ] );
instance = windowManager.openWindow( messageDialog, {
title: title,
message: message,
verbose: options && options.verbose,
actions: buttons
} );
instance.opened.then( function() {
if ( options && options.unescape ) {
// Unescape escaped html
$("label.oo-ui-messageDialog-message").filter(":visible").html( $("label.oo-ui-messageDialog-message").filter(":visible").text().replace(/<(\/?(?:br|p|ul|li)\s?\/?)>/g,"<$1>") );
// Resize dialogue to fit
messageDialog.updateSize();
}
} );
instance.closed.then( function ( data ) {
if ( data && data.action ) {
callback(data.action);
} else {
callback(null);
}
windowManager.destroy();
} );
};
/* -- Title-related functions -- */
// Check namespace
XFDcloser.checkNamespace = function(pagetitle, expectedNamespaceId) {
var t = new mw.Title( pagetitle );
if ( expectedNamespaceId !== -5 ) {
//true for in expected namespace, false otherwise
return (t.getNamespaceId() === expectedNamespaceId);
} else {
//MFD & RFD can be in any namespace
return true;
}
};
// Get a page's talk page
XFDcloser.getTalkPage = function(p) {
var t = new mw.Title( p );
if ( t.getNamespaceId()%2 === 1 ) {
// Page is itself a talk page
return "";
}
return mw.Title.newFromText( t.getMain(), t.getNamespaceId()+1 ).getPrefixedText();
};
// Get a talk page's subject page
XFDcloser.getSubjectPage = function(p) {
var t = new mw.Title( p );
if ( t.getNamespaceId()%2 !== 1 ) {
// Page is itself a subject page
return "";
}
return mw.Title.newFromText( t.getMain(), t.getNamespaceId()-1 ).getPrefixedText();
};
// Clean up page title text, including replacing underscores with spaces
XFDcloser.getPageText = function(p) {
var t = mw.Title.newFromText( decodeURIComponent(p) );
if (t) {
return t.getPrefixedText();
} else {
//FORLATER: is this needed and/or the best way to handle a null t?...
// t should only be null if p is a bad page title...
return p.replace(/_/g, " ");
}
};
/* -- Make warning text if initial sanity checks fail -- */
XFDcloser.doSanityChecks = function(nom_data, input_data, relisting) {
if ( input_data == null ) input_data = false;
if ( relisting !== true ) relisting = false;
var warnings = "";
//Check for mass actions:
if ( (!relisting&&(!input_data||input_data.after!=="noAction")) || (relisting&&(xfdSetting.xfd_type==="ffd"||xfdSetting.xfd_type==="tfd")) ) {
if ( nom_data.pages.length > 3 ) {
warnings += "<p>Mass actions will be peformed (" + nom_data.pages.length +
" nominated pages detected).";
if ( nom_data.pages.length > 50 ) {
warnings += "<br/>(only the first 50 pages may be processed, depending on the " +
"closing options selected)</p>";
} else {
warnings += "</p>";
}
}
}
//Check target page namespace:
if (input_data && input_data.target && !XFDcloser.checkNamespace(input_data.target, xfdSetting.ns_number)) {
warnings += "<p>Target page \"" + input_data.target + "\" is not in the " +
xfdc.namespaces[(xfdSetting.ns_number).toString()] +
" namespace.</p>";
}
//Check namespaces of nominated pages
var wrong_ns_pages = "";
for ( var i=0; i<nom_data.pages.length; i++ ) {
if ( !nom_data.correctNS[i] ) {
wrong_ns_pages += "<li>" + nom_data.pages[i] + "</li>";
}
}
if ( wrong_ns_pages !== "" ) {
warnings += "The following pages are not in the " +
xfdc.namespaces[(xfdSetting.ns_number).toString()] +
" namespace:<ul>" + wrong_ns_pages + "</ul>";
}
return warnings;
};
/* -- Retrieve extra info for pages/nomination -- */
XFDcloser.getExtraInfo = function(jquery_selector) {
var pages = $(jquery_selector).data("pages");
var section_header = $(jquery_selector).data("section_header");
var nom_page = $(jquery_selector).data("nom_page");
// Discussion link:
var nom_anchor = "";
if (xfdSetting.xfd_type !== "afd") {
nom_anchor = "#" + mw.util.wikiUrlencode(section_header);
}
disc_link = nom_page + nom_anchor;
$(jquery_selector).data("disc_link", disc_link);
// Talk pages, existence checks, namespace checks:
apiFailedCallback_getExtraInfo = function(api_code, api_result) {
// change to basic-closure mode
$(jquery_selector).data("pages", [-1]);
$(jquery_selector).show();
// show error message
var $details = XFDcloser.makeApiErrorMsg(api_code, api_result);
$(jquery_selector + "_loading")
.attr("class", "error")
.css({"display": "inline", "font-size":"90%"})
.text("[Error retrieving page information (reload the page to try again) ")
.append($details)
.append("]");
};
apiCallback_getPagesInfo = function(result) {
var page_ids = result.query.pageids;
var talkPages = new Array (page_ids.length); // an array for just the talk pages
var pageExists = new Array (page_ids.length);
var talkExists = new Array (page_ids.length);
var correctNS = new Array (page_ids.length);
for (var i=0; i<page_ids.length; i++) {
title = result.query.pages[ page_ids[i] ].title;
j = pages.indexOf(title);
if ( j === -1 ) {
$(jquery_selector).data("pages", [-1]);
$(jquery_selector).show();
$(jquery_selector + "_loading")
.html("[Error retrieving page information (reload the page to try again) " +
"<span style='font-size:90%;'>Details: <i>API query result " +
"included unexpected page title \"" + XFDcloser.makeLink(title) + "\"</i></span>]")
.attr("class", "error")
.css({"display": "inline", "font-size":"90%"});
return;
}
talkPages[j] = XFDcloser.getTalkPage(title);
pageExists[j] = page_ids[i] > 0;
talkExists[j] = result.query.pages[ page_ids[i] ].talkid > 0;
if ( xfdSetting.xfd_type === "mfd" || xfdSetting.xfd_type === "rfd" ) {
correctNS[j] = true;
} else {
correctNS[j] = result.query.pages[ page_ids[i] ].ns === xfdSetting.ns_number;
}
}
$(jquery_selector)
.data("talkPages", talkPages)
.data("pageExists", pageExists)
.data("talkExists", talkExists)
.data("correctNS", correctNS);
//Check if nom_date is also done
if ( $(jquery_selector).data("nom_date") != null ) {
//All done
$(jquery_selector).show();
$(jquery_selector + "_loading").remove();
}
};
if ( pages[0] !== -1 ) {
//get page info from api
new mw.Api().get( {
action: 'query',
titles: pages.join("|"),
prop: 'info',
inprop: 'talkid',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getPagesInfo )
.fail( apiFailedCallback_getExtraInfo );
} else {
//Check if nom_date is also done
if ( $(jquery_selector).data("nom_date") != null ) {
//All done
$(jquery_selector).show();
$(jquery_selector + "_loading").remove();
}
}
// Nomination date:
var nomdate = "";
apiCallback_getNomInfo = function(result) {
//get nomination date from when nom page was created
var p_id = result.query.pageids[0];
var timestamp = result.query.pages[p_id].revisions[0].timestamp;
var d = new Date(timestamp);
nomdate = d.getUTCDate().toString()+' '+xfdc.monthnames[d.getUTCMonth()]+' '+d.getUTCFullYear().toString();
$(jquery_selector).data("nom_date", nomdate);
//Check if getPagesInfo is also done
if ( pages[0] === -1 || $(jquery_selector).data("talkPages") != null ) {
//All done
$(jquery_selector).show();
$(jquery_selector + "_loading").remove();
}
};
if (xfdSetting.xfd_type !== "afd" && xfdSetting.xfd_type !== "mfd" ) {
nomdate = nom_page.split(xfdSetting.path)[1];
$(jquery_selector).data("nom_date", nomdate);
if ( xfdSetting.xfd_type === "rfd" && $(jquery_selector).data("first_date") === "" ) {
// For an RfD with no first comment date detected, use the nom page date in dmy format
$(jquery_selector).data("first_date", nomdate.replace(/(\d+) (\w*) (\d+)/g, "$3 $2 $1"));
}
//Check if getPagesInfo is also done
if ( pages[0] === -1 || $(jquery_selector).data("talkPages") != null ) {
//All done
$(jquery_selector).show();
$(jquery_selector + "_loading").remove();
}
} else {
//Api query to get nomination page content
new mw.Api().get( {
action: 'query',
titles: nom_page,
prop: 'revisions',
rvprop: 'timestamp',
rvdir: 'newer',
rvlimit: '1',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getNomInfo )
.fail( apiFailedCallback_getExtraInfo );
}
};
/* -- Resolving redirects -- */
// If nominated pages are redirects (at venues other than RfD), the script can't know if this was
// appropriate, where results such as 'Delete' should be applied to the target, or an out-of-process
// redirection, where results such as 'Delete' should be applied to the redirect
XFDcloser.resolveRedirects = function(nom_data, pass_through, doRelist) {
// If there are no redirects, just get on with closing or relisting
doNext = function() {
if ( doRelist ) {
XFDcloser.processRelist(nom_data, pass_through);
} else {
XFDcloser.processClose(nom_data, pass_through);
}
};
// Callbacks for api query
apiFailedCallback_getRedirectInfo = function(api_code, api_result) {
var $details = XFDcloser.makeApiErrorMsg(api_code, api_result);
$("#XFDcloser-closing")
.attr("class", "error")
.css({"display": "inline", "font-size":"90%"})
.text("[Error checking redirect status of nominated page(s) ")
.append($details)
.append("]");
};
apiCallback_getRedirectInfo = function(result) {
if ( result.query.redirects ) {
// Redirects are present, need to ask user what to do
var redir_from = new Array(result.query.redirects.length);
var redir_to = new Array(result.query.redirects.length);
var redir_list = new Array(result.query.redirects.length);
for (var i=0; i<result.query.redirects.length; i++) {
redir_from[i] = result.query.redirects[i].from;
redir_to[i] = result.query.redirects[i].to;
redir_list[i] = redir_from[i] + " → " + redir_to[i];
}
var redirects_msg = "The following nominated pages are redirects to other pages:<ul><li>" +
redir_list.join("</li><li>") + "</li></ul>";
//Callback for multiButtonConfirm dialog
mbcCallback_useTargets = function(action) {
if ( action === 'accept' ) {
// Build a reference object linking titles to their page ids
var title_ids = {};
for (var tt=0; tt<result.query.pageids.length; tt++) {
title_ids[ result.query.pageids[tt] ] = result.query.pages[ result.query.pageids[tt] ].title;
}
//update nom data
for (var ii=0; ii<redir_from.length; ii++) {
var ndp_index = nom_data.pages.indexOf(redir_from[ii]);
var target_id = XFDcloser.val2key(redir_to[ii], title_ids);
if ( ndp_index !== -1 ) {
nom_data.pages[ndp_index] = redir_to[ii];
nom_data.talkPages[ndp_index] = XFDcloser.getTalkPage(redir_to[ii]);
nom_data.pageExists[ndp_index] = target_id > 0;
nom_data.talkExists[ndp_index] = result.query.pages[target_id].talkid > 0;
if ( xfdSetting.xfd_type === "mfd" || xfdSetting.xfd_type === "rfd" ) {
nom_data.correctNS[ndp_index] = true;
} else {
nom_data.correctNS[ndp_index] = result.query.pages[target_id].ns === xfdSetting.ns_number;
}
}
}
doNext();
} else if ( action === 'reject' ) {
//Just get on with closing or relisting
doNext();
} else {
//Abort closing
$("#XFDcloser-closing")
.siblings()
.show()
.end()
.remove();
return;
}
};
XFDcloser.multiButtonConfirm('Use redirects or targets?', redirects_msg, [
{ label: 'Cancel', flags: 'safe' },
{ label: 'Use redirects', action: 'reject' },
{ label: 'Use targets', action: 'accept', flags: 'progressive' }
], mbcCallback_useTargets, {'verbose': true, 'unescape': true} );
} else {
// No redirects present, just get on with closing or relisting
doNext();
}
};
// Get redirect status / targets, if any, from Api
new mw.Api().get( {
action: 'query',
titles: nom_data.pages.join("|"),
redirects: 1,
prop: 'info',
inprop: 'talkid',
indexpageids: 1
} ).done( apiCallback_getRedirectInfo )
.fail( apiFailedCallback_getRedirectInfo );
};
/* -- Messaging- and task-related functions -- */
//Show a task, apply styling if specified, append text if specified
XFDcloser.updateTask = function(output_id, task_index, styling, append_text, remove_selector) {
jquery_selector = "#" + output_id + " > div > p.XFDcloser-task-" + task_index;
if ( styling ) {
$(jquery_selector).show().css(styling);
} else {
$(jquery_selector).show();
}
if ( append_text != null ) {
$(jquery_selector).append(append_text);
//make sure errors are at the end
$errors = $(jquery_selector).children("span.error");
if ($errors.length > 0) {
$errors.detach().appendTo( $(jquery_selector) );
}
}
if ( remove_selector != null ) {
$(jquery_selector).find(remove_selector).remove();
}
};
//Show a task has beeen started
XFDcloser.taskStarted = function(output_id, task_index) {
applystyle = {
"color": "#000090"
};
XFDcloser.updateTask(output_id, task_index, applystyle, "<img class='XFDcloser-working' src='//upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Ajax-loader%282%29.gif/40px-Ajax-loader%282%29.gif' width='20' height='5' />");
};
//Show a task has beeen completed
//FORLATER: Implemenet a third parameter "with errors" : true|false which would cause it to append "Done (with errors)" instead of "Done!".
// Tasks would count completed edits/actions as well as failed edits/actions, and would compare the sum of completed & failed as well
// as the number of completed against the total to do, i.e.
// IF (completed === total) THEN taskFinished(output_id, task_index) ELSE IF (completed + failed === total) THEN taskFinished(output_id, task_index, true)
XFDcloser.taskFinished = function(output_id, task_index) {
applystyle = {
"color": "#005000"
};
XFDcloser.updateTask(output_id, task_index, applystyle, " Done.", "img.XFDcloser-working");
XFDcloser.checkIfAllDone(output_id, true);
};
//Show a task has an error
//FORLATER: better error messagaing system may be to place error messages in separate <p> at the end(?)
XFDcloser.taskError = function(output_id, task_index, error_msg) {
applystyle = {
"color": "#ff0000"
};
XFDcloser.updateTask(output_id, task_index, applystyle, "<span class='error' style='display:inline;font-size:98%;'> [Error: " + error_msg + "]</span>", "img.XFDcloser-working");
if ( xfdc.task_errors[output_id][task_index] !== 1 ) {
xfdc.task_errors[output_id][task_index] = 1;
XFDcloser.checkIfAllDone(output_id);
}
};
//Show a warning for a task
XFDcloser.taskWarning = function(output_id, task_index, warn_msg) {
XFDcloser.updateTask(output_id, task_index, null, "<span class='error' style='display:inline;font-size:98%;color:#A60C7D;'> [" + warn_msg + "]</span>", "img.XFDcloser-working");
};
//Show that everything is done
XFDcloser.allTasksDone = function(output_id, result) {
xfdc.finished++;
if ( result === "relist" ) {
finished_msg = "Discussion <strong>relisted</strong> (reload page to see the actual relist)";
} else {
finished_msg = "Closed as <strong>" + result + "</strong> (reload page to see the actual close)";
}
$("#" + output_id).prepend(finished_msg).prev().css("text-decoration", "line-through");
$("#" + output_id).find(".XFDcloser-inprogress").remove();
};
//Check if tasks are done (including done with errors)
XFDcloser.checkIfAllDone = function(output_id, increment_tasks_completed) {
if (increment_tasks_completed) {
xfdc.tasks_completed[output_id]++;
}
var sum_errors = xfdc.task_errors[output_id].reduce(function(t, v) {
if (isNaN(v)) {
return t;
} else {
return t + v;
}
}, 0);
if (xfdc.tasks_completed[output_id] + sum_errors === xfdc.tasks_to_do[output_id]) {
nom_data = $("#" + output_id).data();
res = nom_data.res;
XFDcloser.allTasksDone(output_id, res);
}
};
// Api failure: When there is an api fail, the more specific failure callback function uses this
// to pass the message on
XFDcloser.Api_failed = function(output_id, task_index, attempted_action, api_code, api_result ) {
var $details = XFDcloser.makeApiErrorMsg(api_code, api_result);
var $msg = $("<span>")
.append("Could not " + attempted_action + " ")
.append($details);
XFDcloser.taskError( output_id, task_index, $msg.html() );
};
//Notify that tasks are aborted - discussion was already closed
XFDcloser.abortTasks = function(output_id, tasks) {
for (var ii = 0; ii < tasks.length; ii++) {
XFDcloser.updateTask(output_id, tasks[ii],
{"color": "#cc5555"},
"<span class='error' style='display:inline;font-size:98%;'> Aborted</span>",
"img.XFDcloser-working");
}
xfdc.finished++;
var finished_msg = "<strong>Aborted closing</strong>: discussion was already closed (reload page to see the actual close)";
$("#" + output_id).prepend(finished_msg).prev().css("text-decoration", "line-through");
$("#" + output_id).find(".XFDcloser-inprogress").remove();
};
/* -- Show/hide closed discussions -- */
$(document).ready( function () {
$( document.body ).append('<div id="XFDcloser-showhide">'+
'<a id="XFDcloser-showhide-hide">Hide closed discussions</a>'+
'<a id="XFDcloser-showhide-show">Show closed discussions</a>'+
'</div>');
$("#XFDcloser-showhide").css({
"bottom": "0",
"display": "block",
"position": "fixed",
"right": "0",
"z-index": "100",
"padding": "5px",
"box-shadow": "0 2px 4px rgba(0,0,0,0.5)",
"background-color": "#FEF9E6",
"border": "1px solid #aaa",
"border-radius": "5px",
"font-size": "85%"
});
$('#XFDcloser-showhide-show').hide();
$('#XFDcloser-showhide-hide').on('click', function() {
$(".xfd-closed, .tfd-closed").hide();
$('#XFDcloser-showhide-show').show();
$('#XFDcloser-showhide-hide').hide();
});
$('#XFDcloser-showhide-show').on('click', function() {
$(".xfd-closed, .tfd-closed").show();
$('#XFDcloser-showhide-show').hide();
$('#XFDcloser-showhide-hide').show();
});
} );
/* == Set up inline links and set data for each discussion == */
/* ********************************************************** */
//Fix for WP:TFD#Completed_discussions
if ( xfdSetting.xfd_type === "tfd" ) {
$("#Completed_discussions").parent().nextAll("h4").children().addClass("XFDcloser-ignore");
}
$(xfdSetting.html.head + " > span.mw-headline").not(".XFDcloser-ignore").each(function( headings_index ) {
$(".mw-headline-number", this).prependTo($(this).parent()); // fix for "Auto-number headings" preference
var section_header = $(":first-child", this).text();
if (!section_header) { // section header wasn't a link
section_header = $(this).text();
$(this).wrapInner("<span></span>"); // wrap with span so it can be styled later
}
var discussion_element_class;
if (xfdSetting.xfd_type === "afd") { //closed afd's have headings inside the coloured div
discussion_element_class = $(this).parent().parent().attr("class");
if (!discussion_element_class.includes("xfd-closed")) {
discussion_element_class = "";
}
} else {
discussion_element_class = $(this).parent().next().attr("class");
}
if ( discussion_element_class ) { // only closed discussion have element with any class set
if (xfdSetting.xfd_type !== "afd") { // closed afd's already have these classes
$(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, .autoCloserButton").attr('href');
var editsection = sectionlink.split("section=")[1];
if ( editsection.search("T")<0 ) {
// if true, we're on the subpage
if ( xfdSetting.transcludedOnly ) {
//pages like WP:WikiProject Deletion sorting/New York should only have links added to transcluded section
return;
}
nom_page = XFDcloser.getPageText(thispage);
} else {
// if false, section is transcluded from a subpage
nom_page = XFDcloser.getPageText( sectionlink.split("title=")[1].split("&")[0] );
if ( nom_page === "Wikipedia:Redirects for discussion/Header" || nom_page === "Wikipedia:Redirect/Deletion reasons" ) {
// ignore headings transcuded from these pages
return;
}
editsection = editsection.substr(2); // remove "T-" from section number
}
var pages=[];
var firstdate = "";
if ( xfdSetting.xfd_type === "cfd" ) {
//CFDs will have basic closure only - no further actions (per WT:CFD discussion https://en.wikipedia.org/wiki/Wikipedia_talk:Categories_for_discussion/Archive_16#Closure_script )
pages = [-1];
} else if ( xfdSetting.xfd_type === "rfd" || xfdSetting.xfd_type === "mfd" ) {
//For MFD, closed discussion are within a collapsed table
$("table.collapsible").has("div.xfd-closed").addClass("xfd-closed");
// MFD & RFD have nominated page links prior to span with classes plainlinks, lx
var $pages_mr = $(this).parent().nextUntil(xfdSetting.html.head + ", div.xfd-closed, table.xfd-closed")
.find(xfdSetting.html.listitem).has("span.plainlinks.lx").children("span")
.filter(":first-child").children("a, span.plainlinks:not(.lx)").filter(":first-child");
$pages_mr.each(function( ii ) {
pages[ii] = XFDcloser.getPageText($(this).text());
});
var disc_text = $(this).parent().nextUntil(xfdSetting.html.head + ", div.xfd-closed, table.xfd-closed").text();
if ( xfdSetting.xfd_type === "rfd" ) {
// ignore relisted discussions, and non-boxed closed discussions
if ( disc_text.includes("Relisted, see Wikipedia:Redirects for discussion") ||
disc_text.includes("Closed discussion, see full discussion") ) {
return;
}
var firstdate_patt = /(?:\d\d:\d\d, )(\d{1,2} \w+ \d{4})(?: \(UTC\))/;
var firstdate_match = firstdate_patt.exec(disc_text);
if (firstdate_match != null ) {
firstdate = firstdate_match[1];
}
}
} else {
// AFD & TFD have nominated page links inside span with classes plainlinks, nourlexpansion
var $pages = $(this).parent().nextUntil(xfdSetting.html.head + ", div.xfd-closed")
.find(xfdSetting.html.listitem + " > span.plainlinks.nourlexpansion")
.filter(":nth-child(" + xfdSetting.html.nthSpan + ")").children("a")
.filter(":first-child");
//var pages = new Array($pages.length);
$pages.each(function( ii ) {
pages[ii] = XFDcloser.getPageText($(this).text());
});
}
// sanity check - is title non-null?
if (pages[0] == null ) {
//Still offer a "basic" close using the section header
pages = [-1];
}
// quick closes
var quick_close_span = "";
if ( pages[0] !== -1 ) {
quick_close_span = "<span style='margin-left:13px;font-size:92%;' class='XFDcloser-link-quickclose'>" +
"[<a class='XFDcloser-link-quickclose-toggle' title='quickClose discussion...'>quickClose</a>" +
"<span class='XFDcloser-link-quickclose-options' style='display:none;'> " +
"<a style='cursor:pointer;' title='quickKeep: close as \"keep\", remove nomination " +
"templates, add old xfd templates to talk pages' class='XFDcloser-link-qk'>qK</a>" +
" <strong>·</strong> " +
"<a style='cursor:pointer;' title='quickDelete: close as \"delete\", delete nominated " +
"pages & their talk pages & redirects, optionally unlink backlinks" + "' class='XFDcloser-link-qd'>qD</a>" +
" <span title='Cancel' class='XFDcloser-quickclose-cancel'></span>" +
"</span>" +
"]" +
"</span>";
}
// Add links after heading
$(this).append("<span id=XFDClosing_" + headings_index + " class='XFDClosing' style='font-size:85%;margin-left:13px;font-weight:normal'>" +
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' title='Close discussion...' class='XFDcloser-link-close'>Close</a>]</span>" +
quick_close_span +
"<span style='margin-left:13px;'>[<a style='cursor:pointer;' title='Relist discussion...' class='XFDcloser-link-relist'>Relist</a>]</span>" +
"</span>" +
"<span id='XFDClosing_" + headings_index + "_loading' style='font-size:85%;margin-left:13px;font-weight:normal;'>[XFDcloser loading...]</span>");
// Store nomination data
$("#XFDClosing_" + headings_index).hide()
.data("pages", pages)
.data("nom_page", nom_page)
.data("section_header", section_header)
.data("editsection", editsection)
.data("close_span_id", "XFDClosing_" + headings_index)
.data("first_date", firstdate);
// Get extra data to store - talk pages, correct namespace, page existance, talk page existance, discussion link, nomination date
XFDcloser.getExtraInfo("#XFDClosing_" + headings_index);
}
}); //end of .each()
// CFDs don't get relisted
if (xfdSetting.xfd_type === "cfd") {
$("a.XFDcloser-link-relist").parent().empty();
}
// Only TFD allows non-admins to close as "delete" (by listing as "orphan" in holding cell)
if ( !xfdc.isSysop ) {
if ( xfdSetting.xfd_type !== "tfd" ) {
$("a.XFDcloser-link-qd").remove();
} else {
$("a.XFDcloser-link-qd").attr("title", "quickDelete: close as \"delete\", tag nominated " +
"templates with {" + "{being deleted}" + "}, add nominated templates to the holding cell " +
"as \"orphan\"");
}
}
//Adjust qd description for RfD
if ( xfdSetting.xfd_type === "rfd" ) {
$("a.XFDcloser-link-qd").attr("title", "quickDelete: close as \"delete\", delete nominated " +
"pages & their talk pages");
}
// When a [Close] link is clicked:
$("a.XFDcloser-link-close").click(function(){
$(this).parent().parent().children().hide().last().after("<span id='XFDcloser-closing'>Closing...</span>");
var nom_data = $(this).parent().parent().data();
XFDcloser.openInterface(nom_data, false);
});
// When a [Relist] link is clicked:
$("a.XFDcloser-link-relist").click(function(){
$(this).parent().parent().children().hide().last().after("<span id='XFDcloser-closing'>Relisting...</span>");
var nom_data = $(this).parent().parent().data();
XFDcloser.openInterface(nom_data, true);
});
// When [QuickClose] is clicked, show quick close links
$("a.XFDcloser-link-quickclose-toggle").click(function(){
$(this).hide().next().show();
});
// Cancelling QuickClose
$(".XFDcloser-quickclose-cancel")
.html(" x ")
.css({
"cursor": "pointer",
"border": "1px solid #777",
"border-radius": "10px",
"font-weight": "bold",
"font-size": "90%",
"color": "#777",
"padding": "0px",
"margin": "0px 1px"
})
.click(function(){
$(this).parent().hide().prev().show();
});
//When a qK link is clicked:
$("a.XFDcloser-link-qk").click(function(){
var $XFDClosing_span = $(this).parent().parent().parent();
$XFDClosing_span.children().hide().last().after("<span id='XFDcloser-closing'>Closing...</span>");
var nom_data = $XFDClosing_span.data();
//Processing function, can be used as a callback
var process_qK = function(action) {
if ( action === "proceed" ) {
qk_input_data = {
result: "keep",
resultPunct: ".",
rationale: "",
after: "doKeepActions"
};
$XFDClosing_span.data("res", "keep");
if ( xfdSetting.xfd_type==="rfd" ) {
// no need to resolve redirects - just start processing the close
XFDcloser.processClose(nom_data, qk_input_data);
} else {
// need to check for redirects before proceeding
XFDcloser.resolveRedirects(nom_data, qk_input_data, false);
}
} else {
$XFDClosing_span.children().show().last().remove();
return;
}
};
//Warn if mass actions will be peformed
var warnings = XFDcloser.doSanityChecks(nom_data);
if (warnings.length) {
XFDcloser.multiButtonConfirm('Warning', warnings, [
{ label: 'Cancel', flags: 'safe' },
{ label: 'Continue', action: 'proceed', flags: 'progressive' }
], process_qK, {'verbose': true, 'unescape': true} );
} else {
process_qK("proceed");
}
});
//When a qD link is clicked:
$("a.XFDcloser-link-qd").click(function(){
var $XFDClosing_span = $(this).parent().parent().parent();
$XFDClosing_span.children().hide().last().after("<span id='XFDcloser-closing'>Closing...</span>");
var nom_data = $XFDClosing_span.data();
//Processing function, can be used as a callback
var process_qD = function(action) {
if ( action === "proceed" ) {
if ( xfdc.isSysop ) {
qd_input_data = {
result: "delete",
resultPunct: ".",
rationale: "",
after: "doDeletion",
deletetalk: true,
deleteredir: true
};
if ( xfdSetting.xfd_type === "afd" || xfdSetting.xfd_type === "ffd" ) {
qd_input_data.unlinkbackl = true;
}
if ( xfdSetting.xfd_type === "rfd" ) {
qd_input_data.deleteredir = false;
}
} else if ( xfdSetting.xfd_type === "tfd" ) {
qd_input_data = {
result: "delete",
rationale: "",
after: "holdingCell",
holdingcell: "ready",
};
} else {
//currently non-admins can only close TFDs as delete
$XFDClosing_span.children().show().last().remove();
return;
}
$XFDClosing_span.data("res", "delete");
if ( xfdSetting.xfd_type==="rfd" ) {
// no need to resolve redirects - just start processing the close
XFDcloser.processClose(nom_data, qd_input_data);
} else {
// need to check for redirects before proceeding
XFDcloser.resolveRedirects(nom_data, qd_input_data, false);
}
} else {
$XFDClosing_span.children().show().last().remove();
return;
}
};
//Warn if mass actions will be peformed
var warnings = XFDcloser.doSanityChecks(nom_data);
if (warnings.length) {
XFDcloser.multiButtonConfirm('Warning', warnings, [
{ label: 'Cancel', flags: 'safe' },
{ label: 'Continue', action: 'proceed', flags: 'progressive' }
], process_qD, {'verbose': true, 'unescape': true} );
} else {
process_qD("proceed");
}
});
/* == Interface-related functions == */
/* ********************************* */
//Show the interface
XFDcloser.openInterface = function(nom_data, relisting) {
//HTML for interface
var $interfaceDiv = $('<div>')
.attr('id', 'closeXFD-interface')
.css({
"background-color": "#f0f0f0",
"padding": "0.5em 1em",
"font-size": "110%"
}).html(
'<h4 id="closeXFD-interface-header" class="closeXFD-showFor-relisting"><span id="closeXFD-interface-header-action">Closing</span> discussion <em>' + nom_data.section_header + '</em> <span id="closeXFD-pagecount" style="font-size:80%;">(<span id="closeXFD-pagecount-pages" style="background:#ff8;padding:1px;">' + nom_data.pages.length + ' pages</span> <a id="closeXFD-pagecount-show" style="display:inherit;">[show]</a><a id="closeXFD-pagecount-hide" style="display:none;">[hide]</a>)</span></h4>'+
'<ul id="closeXFD-nominatedpages" style="display:none;font-size:90%;" class="closeXFD-showFor-relisting"><li>' + nom_data.pages.join('</li><li>') + '</li></ul>'+
'<hr class="closeXFD-showFor-relisting">'+
'<div style="text-align:center;clear:both;" class="closeXFD-nonSysop-only">'+
'<em>See the <a href="https://en.wikipedia.org/wiki/WP:NACD" target="_blank">WP:NACD</a> guideline for advice on appropriate and inappropriate closures</em>' +
'</div><hr class="closeXFD-nonSysop-only">' +
'<div style="float:left; width:99%; padding-bottom:1%;" id="closeXFD-resultContainer"><strong style="margin-right: 2em;">Result</strong> '+
'<span style="white-space:nowrap;">( '+
'<input type="checkbox" name="closeXFD-speedy" id="closeXFD-speedy" /><label for="closeXFD-speedy">Speedy</label>'+
' )</span><br/>'+
'<span class="closeXFD-option"><input type="radio" name="closeXFD-result" class="closeXFD-keepResult" id="closeXFD-result-keep" /><label for="closeXFD-result-keep">Keep</label></span>'+
'<span class="closeXFD-option closeXFD-FFD-na"><input type="radio" name="closeXFD-result" class="closeXFD-keepResult" id="closeXFD-result-redir" /><label for="closeXFD-result-redir">Redirect</label></span>'+
'<span class="closeXFD-option closeXFD-RFD-only"><input type="radio" name="closeXFD-result" class="closeXFD-keepResult" id="closeXFD-result-softredir" /><label for="closeXFD-result-softredir">Soft redirect</label></span>'+
'<span class="closeXFD-option"><input type="radio" name="closeXFD-result" class="closeXFD-keepResult" id="closeXFD-result-nocon" /><label for="closeXFD-result-nocon">No consensus</label></span>'+
'<span class="closeXFD-option closeXFD-FFD-na closeXFD-RFD-na"><input type="radio" name="closeXFD-result" id="closeXFD-result-merge" /><label for="closeXFD-result-merge">Merge</label></span>'+
'<span class="closeXFD-option closeXFD-sysop-only closeXFD-nonSysop-TFDonly"><input type="radio" name="closeXFD-result" class="closeXFD-deleteResult" id="closeXFD-result-delete" /><label for="closeXFD-result-delete">Delete</label></span>'+
'<span class="closeXFD-option closeXFD-nonSysop-only closeXFD-TFD-na"><input type="radio" name="closeXFD-result" class="closeXFD-deleteResult" id="closeXFD-result-delete-disabled" disabled="disabled" /><label for="closeXFD-result-delete-disabled" style="color:#777;">Delete <span title="Non-admin closure is not appropriate when the result will require action by an administrator (per [[WP:BADNAC]])" class="closeXFD-interface-tooltip"></span></label></span>'+
'<span class="closeXFD-option closeXFD-sysop-only closeXFD-RFD-na" id="closeXFD-resultContainer-softdel"><input type="radio" name="closeXFD-result" class="closeXFD-deleteResult" id="closeXFD-result-softdel" /><label for="closeXFD-result-softdel">Soft delete</label></span>'+
'<span class="closeXFD-option"><input type="radio" name="closeXFD-result" id="closeXFD-result-custom" /><label for="closeXFD-result-custom">Custom</label></span>'+
'<p id="closeXFD-closetype-notes"></p>'+
'</div>'+
'<div style="clear:both;padding-bottom:1%;" id="closeXFD-resultContainer-custom" class="closeXFD-visibleFor-customResult"> '+
'<label for="closeXFD-result-custom-input">Custom result:</label>'+
'<input type="text" name="closeXFD-result-custom-input" id="closeXFD-result-custom-input" />'+
'</div>'+
'<div style="clear:both;padding-bottom:1%;" id="closeXFD-resultContainer-target" class="closeXFD-visibleFor-mergeResult closeXFD-visibleFor-redirectResult">'+
'<label id="closeXFD-result-target-label" for="closeXFD-result-target">Target:</label> '+
'<input type="text" name="closeXFD-result-target" id="closeXFD-result-target" />'+
'</div>'+
'<div style="clear:both;" class="closeXFD-showFor-relisting"><strong id="closeXFD-rationale-label">Additional rationale</strong> (optional):<br/>'+
'<textarea id="closeXFD-rationale" rows=4 style="width:99%;"></textarea>'+
'</div>'+
'<div style="clear:both;padding-bottom:1%;"> '+
'<input type="checkbox" name="closeXFD-rationale-sentence" id="closeXFD-rationale-sentence" /><label for="closeXFD-rationale-sentence">Rationale is not a new sentence</label>'+
'</div>'+
'<div id="closeXFD-afterContainer" class="closeXFD-listOfOptions"><strong>After closing:</strong><br/>'+
'<span class="closeXFD-visibleFor-keepResult closeXFD-visibleFor-customResult closeXFD-basic-na"><input type="radio" name="closeXFD-after" id="closeXFD-after-doKeepActions" /><label for="closeXFD-after-doKeepActions">Update pages and talk pages <span title="Remove nomination templates, and add old xfd templates to talk pages" class="closeXFD-interface-tooltip"></span> </label><br /></span>'+
'<span class="closeXFD-visibleFor-mergeResult closeXFD-basic-na"><input type="radio" name="closeXFD-after" id="closeXFD-after-doMergeActions" /><label for="closeXFD-after-doMergeActions">Update pages and talk pages <span title="Replace nomination templates with merge templates, and add old xfd templates to talk pages" class="closeXFD-interface-tooltip"></span></label><br /></span>'+
'<span class="closeXFD-visibleFor-redirectResult closeXFD-basic-na"><input type="radio" name="closeXFD-after" id="closeXFD-after-doRedirectActions" /><label for="closeXFD-after-doRedirectActions">Redirect pages and update talk pages <span title="Redirect nominated pages to the specified target, and add old xfd templates to talk pages" class="closeXFD-interface-tooltip"></span></label><br /></span>'+
'<span class="closeXFD-visibleFor-deleteResult closeXFD-visibleFor-customResult closeXFD-sysop-only closeXFD-basic-na"><input type="radio" name="closeXFD-after" id="closeXFD-after-doDeletion" /><label for="closeXFD-after-doDeletion">Delete pages <span title="Delete nominated pages and (unless otherwise specified) their talk pages" class="closeXFD-interface-tooltip"></span></label><br /></span>'+
'<span class="closeXFD-visibleFor-deleteResult closeXFD-visibleFor-customResult closeXFD-TFD-only closeXFD-basic-na"><input type="radio" name="closeXFD-after" id="closeXFD-after-holdingCell" /><label for="closeXFD-after-holdingCell">List pages at holding cell <span title="Replace nomination template with {' + '{Being deleted}' + '}, and list at the specified holding cell section" class="closeXFD-interface-tooltip"></span></label><br /></span>'+
'<span class="closeXFD-visibleFor-deleteResult closeXFD-visibleFor-customResult closeXFD-nonSysop-only closeXFD-basic-na"><input type="radio" name="closeXFD-after" id="closeXFD-after-tagSpeedy" /><label for="closeXFD-after-tagSpeedy">Tag for speedy deletion <span title="Tag nominated pages for G6 speedy deletion, and (unless otherwise specified) tag their talk pages for G8 speedy deletion" class="closeXFD-interface-tooltip"></span></label><br /></span>'+
'<span><input type="radio" name="closeXFD-after" id="closeXFD-after-noAction" /><label for="closeXFD-after-noAction">No automated actions</label><br /></span>'+
'</div>'+
'<div id="closeXFD-optionsContainer" class="closeXFD-listOfOptions closeXFD-visibleFor-deleteResult closeXFD-visibleFor-customResult closeXFD-basic-na"><strong>Options:</strong><br/>'+
'<input type="checkbox" name="closeXFD-option-deletetalk" id="closeXFD-option-deletetalk" /><label for="closeXFD-option-deletetalk">Do not <span class="closeXFD-sysop-only">delete talk pages</span><span class="closeXFD-nonSysop-only">tag talk pages for speedy deletion</span></label><br /></span>'+
'<span class="closeXFD-sysop-only closeXFD-RFD-na"><input type="checkbox" name="closeXFD-option-deleteredir" id="closeXFD-option-deleteredir" /><label for="closeXFD-option-deleteredir">Also delete redirects</label><br /></span>'+
'<span class="closeXFD-TFD-na closeXFD-MFD-na"><input type="checkbox" name="closeXFD-option-unlinkbackl" id="closeXFD-option-unlinkbackl" /><label for="closeXFD-option-unlinkbackl">Unlink backlinks</label><br /></span>'+
'<span class="closeXFD-sysop-only closeXFD-FFD-na"><input type="checkbox" style="visibility:hidden;" /><a id="closeXFD-option-deleteAndRedir">Delete and redirect...</a></span>'+
'</div>'+
'<div id="closeXFD-redirectOptionsContainer" class="closeXFD-listOfOptions closeXFD-visibleFor-redirectResult closeXFD-basic-na" style="display:none;"><strong>Options:</strong><br/>'+
'<span id="closeXFD-redirectOptionsContainer-deleteFirst" class="closeXFD-sysop-only"><input type="checkbox" name="closeXFD-redirectOption-deleteFirst" id="closeXFD-redirectOption-deleteFirst" /><label for="closeXFD-redirectOption-deleteFirst">Delete before redirecting</label><br /></span>'+
'<span id="closeXFD-rcatOptionsContainer-on">'+
'<input type="radio" name="closeXFD-rcatOptions" id="closeXFD-rcatOptions-on" />'+
'<label for="closeXFD-result-redir-rcats"><a href="https://en.wikipedia.org/wiki/Template:R_template_index" target="_blank">Rcats</a>: <span title="Full markup required, e.g. "{'+'{R to section}'+'}". Multiple rcats can be specified, e.g. "{'+'{R from book}'+'}{'+'{R to anchor}'+'}". Leave blank if unsure which rcat to use." class="closeXFD-interface-tooltip"></span></label>'+
'</span><input type="text" name="closeXFD-result-redir-rcats" id="closeXFD-result-redir-rcats" /><br />'+
'<span id="closeXFD-rcatOptionsContainer-off"><input type="radio" checked name="closeXFD-rcatOptions" id="closeXFD-rcatOptions-off" /><label for="closeXFD-redirectOption-rcats-off">Do not add rcats <span title="Most redirects should have an rcat specified. Only use this option if you are sure that no rcats are appropriate." class="closeXFD-interface-tooltip"></span></label></span>'+
'</div>'+
'<div id="closeXFD-holdingcellContainer" class="closeXFD-basic-na">'+
'<div id="closeXFD-holdingcellsections" class="closeXFD-listOfOptions closeXFD-visibleFor-deleteResult closeXFD-TFD-only "><strong>Holding cell section:</strong><br/>'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-review" /><label for="closeXFD-holdingcell-review">Review</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-convert" /><label for="closeXFD-holdingcell-convert">Convert</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-substitute" /><label for="closeXFD-holdingcell-substitute">Substitute</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-orphan" /><label for="closeXFD-holdingcell-orphan">Orphan</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-ready" /><label for="closeXFD-holdingcell-ready">Ready for deletion</label>'+
'</div>'+
'<div id="closeXFD-holdingcellsections-merge" class="closeXFD-listOfOptions closeXFD-visibleFor-mergeResult closeXFD-TFD-only"><strong>Holding cell section:</strong><br/>'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-merge-arts" /><label for="closeXFD-holdingcell-merge-arts">Merge (Arts)</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-merge-geopolgov" /><label for="closeXFD-holdingcell-merge-geopolgov">Merge (Geography, politics and governance)</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-merge-religion" /><label for="closeXFD-holdingcell-merge-religion">Merge (Religion)</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-merge-sports" /><label for="closeXFD-holdingcell-merge-sports">Merge (Sports)</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-merge-other" /><label for="closeXFD-holdingcell-merge-other">Merge (Other)</label><br />'+
'<input type="radio" name="closeXFD-holdingcell" id="closeXFD-holdingcell-merge-meta" /><label for="closeXFD-holdingcell-merge-">Merge (Meta)</label>'+
'</div>'+
'</div>'+
'<div style="text-align:center;clear:both;" id="closeXFD-interface-buttons" class="closeXFD-showFor-relisting">'+
'<button id="closeXFD-interface-closedisc" style="margin:1em;">Close Discussion</button>'+
'<button id="closeXFD-interface-preview" style="margin:1em;">Preview</button>'+
'<button id="closeXFD-interface-relistdisc" style="margin:1em;" class="closeXFD-showFor-relisting closeXFD-relist-only">Relist Discussion</button>'+
'<button id="closeXFD-interface-previewRelist" style="margin:1em;" class="closeXFD-showFor-relisting closeXFD-relist-only">Preview</button>'+
'<button id="closeXFD-interface-cancel" style="margin:1em;" class="closeXFD-showFor-relisting">Cancel</button>'+
'</div>'+
'<p id="closeXFD-preview-output" class="closeXFD-showFor-relisting"></p>'
);
var interfaceWindow = new Morebits.simpleWindow( Math.min(900, Math.floor(window.innerWidth*0.8)), Math.floor(window.innerHeight*0.9) );
interfaceWindow.setTitle( "XFDcloser" );
interfaceWindow.addFooterLink("script help", "WP:XFDC");
interfaceWindow.addFooterLink("feedback", "WT:XFDC");
interfaceWindow.setContent( $interfaceDiv.get(0) );
interfaceWindow.display();
$('a.ui-dialog-titlebar-close.ui-corner-all').remove();
//Apply styles
$interfaceDiv.parent().css("background-color", "#f0f0f0");
$('span.closeXFD-option').css({
"white-space": "nowrap",
"min-width": "8em",
"margin-right": "0.3em",
"display": "block",
"float": "left"
}).after("<wbr>");
$('.closeXFD-listOfOptions').css({
"float": "left",
"width": "45%",
"padding-bottom": "1%"
});
$("#closeXFD-preview-output").css({
"background-color": "#ffffff",
"border": "1px solid #777777",
"margin-top": "0px",
"padding": "0px 10px",
"display": "none"
});
$(".closeXFD-interface-tooltip").html(" ? ").css({
"border": "1px solid #33a",
"border-radius": "10px",
"font-weight": "bold",
"font-size": "80%",
"color": "#22a",
"padding": "0px"
});
//Hide fields only available for certain results
$('.closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-redirectResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-customResult').hide();
//Remove non-relevent fields, based on xfdSetting.xfd_type, sysop status, etc
var redirect_label = "Redirect";
if (xfdSetting.xfd_type === "rfd") {
redirect_label = "Retarget";
$('#closeXFD-result-redir').next().text(redirect_label);
$(".closeXFD-RFD-na").remove();
} else {
$(".closeXFD-RFD-only").remove();
}
if (xfdSetting.xfd_type !== "tfd") {
$(".closeXFD-TFD-only").remove();
} else {
$(".closeXFD-TFD-na").remove();
}
if (xfdSetting.xfd_type === "ffd") {
$(".closeXFD-FFD-na").remove();
}
if (xfdSetting.xfd_type === "mfd") {
$(".closeXFD-MFD-na").remove();
}
if (xfdc.isSysop) {
$(".closeXFD-nonSysop-only").remove();
} else if ( xfdSetting.xfd_type === "tfd" ) {
$(".closeXFD-sysop-only").not(".closeXFD-nonSysop-TFDonly").remove();
$("#closeXFD-after-tagSpeedy").parent().remove(); // not currently allowed at any XfD
} else {
$(".closeXFD-sysop-only").remove();
$("#closeXFD-after-tagSpeedy").parent().remove(); // not currently allowed at any XfD
}
//Show/hide page count (or basic close info)
if (nom_data.pages.length === 1 && nom_data.pages[0] !== -1 ) {
$("#closeXFD-pagecount-pages").text("1 page"); //change plural to singular
}
$("#closeXFD-pagecount-show, #closeXFD-pagecount-hide").click(function() {
$("#closeXFD-nominatedpages, #closeXFD-pagecount-show, #closeXFD-pagecount-hide").toggle();
});
//If relisting, adjust labels and remove non-relist stuff
var basic_close_note = "";
if (relisting) {
$("#closeXFD-interface-header-action").text("Relisting");
$("#closeXFD-rationale-label").text("Relist comment");
$("#closeXFD-rationale").attr("rows", 2);
$("#closeXFD-interface, #closeXFD-interface-buttons").children().not(".closeXFD-showFor-relisting").remove();
if (nom_data.pages[0] === -1) {
$("#closeXFD-pagecount-pages").text("basic relist only");
basic_relist_note = '<li>Nominated pages were not detected. You can still relist this ' + xfdSetting.xfd_type.toUpperCase() + ' discussion, but updating the nomination templates will need to be done manually – see <a href="https://en.wikipedia.org/wiki/WP:' + xfdSetting.xfd_type.toUpperCase() + 'AI" target="_blank">WP:' + xfdSetting.xfd_type.toUpperCase() + 'AI</a> for instructions.</li>';
$("#closeXFD-nominatedpages").html(basic_relist_note);
}
} else {
$(".closeXFD-relist-only").remove();
basic_close_note = '<li>Nominated pages were not detected. You can still close this ' + xfdSetting.xfd_type.toUpperCase() + ' discussion, but further actions to implement the close will need to be done manually – see <a href="https://en.wikipedia.org/wiki/WP:' + xfdSetting.xfd_type.toUpperCase() + 'AI" target="_blank">WP:' + xfdSetting.xfd_type.toUpperCase() + 'AI</a> for instructions.</li>';
}
if ( nom_data.pages[0] === -1 && !relisting ) { // Basic close only
$(".closeXFD-basic-na").remove(); // Remove non-applicable options
$("#closeXFD-after-noAction").prop("checked", true); // Make sure "No automated actions" is checked
$("#closeXFD-pagecount-pages").text("basic close only"); // Replace page count/list with basic close info
$("#closeXFD-nominatedpages").html(basic_close_note);
}
//Now show modal
$("#closeXFD-modal").css("display", "");
//On clicking a result, hide & clear fields not for that result, and show fields that are for that result
$('#closeXFD-resultContainer').click(function() {
var selected_after;
if( $('#closeXFD-result-keep').prop('checked') || $('#closeXFD-result-nocon').prop('checked') ) {
//Keep-type result
$('.closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-customResult, .closeXFD-visibleFor-redirectResult').not('.closeXFD-visibleFor-keepResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-redir').next().text(redirect_label);
$('.closeXFD-visibleFor-keepResult').show();
//default 'after' selection:
selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
$('#closeXFD-after-doKeepActions').prop('checked', true);
}
} else if ( $('#closeXFD-result-redir').prop('checked') ) {
//Redirect (keep) result
$('.closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-customResult').not('.closeXFD-visibleFor-redirectResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-target-label').text(redirect_label + " to:");
if (xfdSetting.xfd_type === "afd") {
//Default rcat for AFDs
$("#closeXFD-result-redir-rcats").val("{"+"{R to related topic}"+"}");
}
$('.closeXFD-visibleFor-redirectResult').not("#closeXFD-redirectOptionsContainer").show();
//default 'after' selection:
selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
$('#closeXFD-after-doRedirectActions').prop('checked', true);
$("#closeXFD-redirectOptionsContainer").show();
$('#closeXFD-rcatOptions-on').prop('checked', true);
$('#closeXFD-result-redir-rcats').prop('disabled', false);
}
} else if ( $('#closeXFD-result-softredir').prop('checked') ) {
//Soft redirect result (RFD only)
$('.closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-customResult').not('.closeXFD-visibleFor-redirectResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-target-label').text("Soft redirect to:");
$('.closeXFD-visibleFor-redirectResult').not("#closeXFD-redirectOptionsContainer").show();
//default 'after' selection:
selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
$('#closeXFD-after-doRedirectActions').prop('checked', true);
$("#closeXFD-redirectOptionsContainer").show();
$('#closeXFD-rcatOptions-on').prop('checked', true);
$('#closeXFD-result-redir-rcats').prop('disabled', false);
}
} else if ( $('#closeXFD-result-merge').prop('checked') ) {
//Merge result
$('.closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-customResult, .closeXFD-visibleFor-redirectResult').not('.closeXFD-visibleFor-mergeResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-redir').next().text(redirect_label);
$('#closeXFD-result-target-label').text("Merge to:");
$('.closeXFD-visibleFor-mergeResult').not('#closeXFD-holdingcellsections-merge').show();
//default 'after' selection:
selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
$('#closeXFD-after-doMergeActions').prop('checked', true);
$('#closeXFD-holdingcellsections-merge').show();
}
} else if ( $('#closeXFD-result-custom').prop('checked') ) {
//Custom result
$('.closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-redirectResult').not('.closeXFD-visibleFor-customResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-redir').next().text(redirect_label);
$('.closeXFD-visibleFor-customResult').show();
if ( $('#closeXFD-after-doDeletion').prop('checked') || $('#closeXFD-after-tagSpeedy').prop('checked') ) {
$('#closeXFD-optionsContainer').show();
} else {
$('#closeXFD-optionsContainer').hide();
}
if ( $('#closeXFD-after-holdingCell').prop('checked') ) {
$('#closeXFD-holdingcellsections').show();
} else {
$('#closeXFD-holdingcellsections-merge, #closeXFD-holdingcellsections').hide();
}
} else if ( $('#closeXFD-result-delete').prop('checked') || $('#closeXFD-result-softdel').prop('checked') ) {
//Delete-type result
$('.closeXFD-visibleFor-customResult, .closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-redirectResult').not('.closeXFD-visibleFor-deleteResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-redir').next().text(redirect_label);
$('.closeXFD-visibleFor-deleteResult').not('#closeXFD-OptionsContainer, #closeXFD-holdingcellsections, #closeXFD-holdingcellsections-merge').show();
//default 'after' selection:
selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
$('#closeXFD-after-doDeletion, #closeXFD-after-tagSpeedy').prop('checked', true);
$('#closeXFD-OptionsContainer').show();
$('#closeXFD-option-deleteredir, #closeXFD-option-unlinkbackl').prop('checked', true);
}
}
interfaceWindow.setHeight(Math.floor(window.innerHeight*0.9));
});
//On clicking an after action, show/hide other options as appropriate
$('#closeXFD-afterContainer').click(function() {
//Deletion-related options should be shown if a "deletion actions" is checked, and hidden again when it is unchecked
if ( $('#closeXFD-result-delete').prop('checked') || $('#closeXFD-result-softdel').prop('checked') || $('#closeXFD-result-custom').prop('checked') ) {
if ( $('#closeXFD-after-doDeletion').prop('checked') || $('#closeXFD-after-tagSpeedy').prop('checked') ) {
$('#closeXFD-optionsContainer').show();
} else {
$('#closeXFD-optionsContainer').hide();
}
} else if ( $('#closeXFD-result-redir').prop('checked') || $('#closeXFD-result-softredir').prop('checked') ) {
//Similarly for other redirection-related options
if ( $('#closeXFD-after-noAction').prop('checked') ) {
$('#closeXFD-redirectOptionsContainer').hide();
} else {
$('#closeXFD-redirectOptionsContainer').show();
$('#closeXFD-rcatOptions-on').prop('checked', true);
$('#closeXFD-result-redir-rcats').prop('disabled', false);
}
}
//And holding cell sections should only be shown when appropriate "after" is selected (TFD-only)
if ( xfdSetting.xfd_type === "tfd" ) {
if ( $('#closeXFD-after-doMergeActions').prop('checked') ) {
$('#closeXFD-holdingcellsections-merge').show();
} else if ( $('#closeXFD-after-holdingCell').prop('checked') ) {
$('#closeXFD-holdingcellsections').show();
} else {
$('#closeXFD-holdingcellsections-merge, #closeXFD-holdingcellsections').hide();
}
}
});
//For soft delete, prepend rationale with REFUND message
$('#closeXFD-resultContainer-softdel').children().click(function() {
old_rationale = $('#closeXFD-rationale').val();
if (!old_rationale.includes("[[WP:REFUND]]")) {
$('#closeXFD-rationale').val("[[WP:REFUND]] applies. " + old_rationale);
}
});
//For delete before redirect, adjust result label
$('#closeXFD-redirectOption-deleteFirst').on('change', function() {
var $redir_label = $('#closeXFD-result-redir').next();
var rLabel = redirect_label;
if ( $('#closeXFD-result-softredir').prop('checked') ) {
// overrides for soft redirect
$redir_label = $('#closeXFD-result-softredir').next();
rLabel = "Soft redirect";
}
if ( $redir_label.text() === rLabel ) {
$redir_label.text("Delete and " + rLabel.toLowerCase());
} else {
$redir_label.text(rLabel);
}
});
//Switch from "Delete" to "Delete and redirect"
$('#closeXFD-option-deleteAndRedir').click(function() {
$('.closeXFD-visibleFor-keepResult, .closeXFD-visibleFor-deleteResult, .closeXFD-visibleFor-mergeResult, .closeXFD-visibleFor-customResult').not('.closeXFD-visibleFor-redirectResult').hide().find('input').prop('checked', false).val('');
$('#closeXFD-result-target-label').text(redirect_label + " to:");
if (xfdSetting.xfd_type === "afd") {
//Default rcat for AFDs
$("#closeXFD-result-redir-rcats").val("{"+"{R to related topic}"+"}");
}
$('.closeXFD-visibleFor-redirectResult').not("#closeXFD-redirectOptionsContainer").show();
//default 'after' selection:
selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
$('#closeXFD-after-doRedirectActions').prop('checked', true);
$("#closeXFD-redirectOptionsContainer").show();
$('#closeXFD-rcatOptions-on').prop('checked', true);
$('#closeXFD-result-redir-rcats').prop('disabled', false);
}
$('#closeXFD-redirectOption-deleteFirst').prop('checked', true);
$('#closeXFD-result-redir').prop('checked', true).next().text("Delete and " + redirect_label.toLowerCase());
});
//Switch between rcats being on/off
$('#closeXFD-rcatOptionsContainer-off').children().click(function() {
$('#closeXFD-rcatOptions-off').prop('checked', true);
$('#closeXFD-result-redir-rcats').prop('disabled', true);
});
$('#closeXFD-rcatOptionsContainer-on').children().click(function() {
$('#closeXFD-rcatOptions-on').prop('checked', true);
$('#closeXFD-result-redir-rcats').prop('disabled', false);
});
// Get the modal element
//var $modal = $('#closeXFD-modal');
// --- On button clicks: --- //
// Cancel button clicked
$('#closeXFD-interface-cancel').click(function() {
interfaceWindow.close();
$("#XFDcloser-closing")
.siblings()
.show()
.end()
.remove();
});
// Close discussion button clicked
$('#closeXFD-interface-closedisc').click(function() {
var input_data = new XFDcloser.getInterfaceData();
//If there's an error, show error message
if (input_data.errorID) {
$(".closeXFD-errorNote").parent().css("border", "");
$(".closeXFD-errorNote").remove(); //remove old messages
XFDcloser.showInterfaceError(input_data.errorID);
return;
}
//Processing function, can be used as a callback
var process_close = function(action) {
if ( action === "proceed" ) {
interfaceWindow.close();
// make result avaialable for later
$("#" + nom_data.close_span_id).data("res", input_data.result);
if ( input_data.after==="noAction" || xfdSetting.xfd_type==="rfd" ) {
// no need to resolve redirects - just start processing the close
XFDcloser.processClose(nom_data, input_data);
} else {
// need to check for redirects before proceeding
XFDcloser.resolveRedirects(nom_data, input_data, false);
}
}
};
//If not just closing: check each page (& target), add warning if wrong namespace
//FORLATER: Consider checking if target page exists... perhaps not urgent, given that close
// can be previewed.
var warnings = XFDcloser.doSanityChecks(nom_data, input_data);
if (warnings.length) {
XFDcloser.multiButtonConfirm('Warning', warnings, [
{ label: 'Cancel', flags: 'safe' },
{ label: 'Continue', action: 'proceed', flags: 'progressive' }
], process_close, {'verbose': true, 'unescape': true} );
} else {
process_close("proceed");
}
});
// Preview button clicked
$('#closeXFD-interface-preview').click(function() {
input_data = new XFDcloser.getInterfaceData();
//remove old error messages
$(".closeXFD-errorNote").parent().css("border", "");
$(".closeXFD-errorNote").remove();
if (input_data.result && input_data.errorID!=="#closeXFD-resultContainer-target") {
var preview_wikitext="";
var to_target = "";
if (input_data.target){
to_target = " to " + input_data.targetLink;
}
if (input_data.rationale) {
preview_wikitext = "The result of the discussion was '''" + input_data.result + "'''" + to_target + input_data.resultPunct + " " + input_data.rationale + " " + xfdc.sig;
} else {
preview_wikitext = "The result of the discussion was '''" + input_data.result + "'''" + to_target + ". " + xfdc.sig;
}
new mw.Api().get( {
action: 'parse',
contentmodel: 'wikitext',
text: preview_wikitext,
} ).done(function( result ) {
preview_html = result.parse.text["*"];
$("#closeXFD-preview-output").html(preview_html).show().find("a").attr("target", "_blank");
}).fail(function(api_code, api_result) {
var details = "";
if ( api_code === "http" ) {
details = "<span style='font-size:85%;'>Details: <i>HTTP error: " + api_result.textStatus + "</i></span>"; // api_result contains the jqXHR object
} else if ( api_code === "ok-but-empty" ) {
details = "<span style='font-size:85%;'>Details: <i>Got an empty response from the server</i></span>";
} else {
details = "<span style='font-size:85%;'>Details: <i>API error: " + api_code + "</i></span>";
}
$("#closeXFD-preview-output").html("Error: Preview failed " + details).show();
});
} else {
XFDcloser.showInterfaceError(input_data.errorID);
}
});
// Relist discussion button clicked
$('#closeXFD-interface-relistdisc').click(function() {
var relist_comment = $('#closeXFD-rationale').val().replace(/(\|)(?!(?:[^\[]*]|[^\{]*}))/g, "|");
//Processing function, can be used as a callback
var process_relist = function(action) {
if ( action === "proceed" ) {
interfaceWindow.close();
// make result avaialable for later
$("#" + nom_data.close_span_id).data("res", "relist");
if ( xfdSetting.xfd_type==="ffd" || xfdSetting.xfd_type==="tfd" ) {
XFDcloser.resolveRedirects(nom_data, relist_comment, true);
} else {
XFDcloser.processRelist(nom_data, relist_comment);
}
}
};
var warnings = XFDcloser.doSanityChecks(nom_data, null, true);
if (warnings.length) {
XFDcloser.multiButtonConfirm('Warning', warnings, [
{ label: 'Cancel', flags: 'safe' },
{ label: 'Continue', action: 'proceed', flags: 'progressive' }
], process_relist, {'verbose': true, 'unescape': true} );
} else {
process_relist("proceed");
}
});
// Preview (relisting) button clicked
$('#closeXFD-interface-previewRelist').click(function() {
relist_comment = $('#closeXFD-rationale').val().replace(/(\|)(?!(?:[^\[]*]|[^\{]*}))/g, "|");
var preview_wikitext = "{" + "{Relist|1=" + relist_comment + "}}";
new mw.Api().get( {
action: 'parse',
contentmodel: 'wikitext',
text: preview_wikitext,
} ).done(function( result ) {
preview_html = result.parse.text["*"];
$("#closeXFD-preview-output").html(preview_html).show().find("a").attr("target", "_blank");
}).fail(function(api_code, api_result) {
var details = "";
if ( api_code === "http" ) {
details = "<span style='font-size:85%;'>Details: <i>HTTP error: " + api_result.textStatus + "</i></span>"; // api_result contains the jqXHR object
} else if ( api_code === "ok-but-empty" ) {
details = "<span style='font-size:85%;'>Details: <i>Got an empty response from the server</i></span>";
} else {
details = "<span style='font-size:85%;'>Details: <i>API error: " + api_code + "</i></span>";
}
$("#closeXFD-preview-output").text("Error: Preview failed " + details).show();
});
});
};
XFDcloser.showInterfaceError = function(error_id) {
error_note = '<p class="closeXFD-errorNote" style="color:#f00; font-style:italic; font-size:90%;">Required field!</p>';
$(error_id).css("border", "1px solid #ff0000");
$(error_id).fadeTo( "fast", 0.33 ).fadeTo( "fast", 0.8 ).fadeTo( "fast", 0.4 ).fadeTo( "fast", 1 ).append(error_note);
};
//Get data from interface
XFDcloser.getInterfaceData = function() {
//Result
var selected_result = $('input[name="closeXFD-result"]:checked');
if (typeof $(selected_result).val() == "undefined") {
this.errorID = "#closeXFD-resultContainer"; //error in not choosing a result
return;
}
selected_result_label = selected_result.next().text().toLowerCase();
if (selected_result_label == "custom") {
if( $('#closeXFD-result-custom-input').val().length === 0 ) {
this.errorID = "#closeXFD-resultContainer-custom"; //error in not specifying a custom result
return;
}
this.result = $('#closeXFD-result-custom-input').val();
} else {
this.result = selected_result_label;
}
//Speedy result
if ($('#closeXFD-speedy').prop('checked')) {
this.result = 'speedy ' + this.result;
}
//Soft redirect
if ( selected_result_label == "soft redirect" || selected_result_label == "delete and soft redirect" ) {
this.softredir = true;
//adjust label to simplify code below for target
selected_result_label = "redirect";
}
//Merge/redirect target
if ( selected_result_label == "retarget" || selected_result_label == "delete and retarget" || selected_result_label == "delete and redirect" ) {
//adjust label to simplify code below for target
selected_result_label = "redirect";
}
if (selected_result_label == "merge" || selected_result_label == "redirect" ) {
if( ($("#closeXFD-result-target").length !== 0) && ($('#closeXFD-result-target').val().length === 0) ) {
this.errorID = "#closeXFD-resultContainer-target"; //error in not specifying a target
return;
}
if ($("#closeXFD-result-target").length !== 0) {
var targetTitleObj = mw.Title.newFromText( $('#closeXFD-result-target').val() );
if ( targetTitleObj ) {
this.target = targetTitleObj.getPrefixedText();
var targetFrag = "";
if ( targetTitleObj.getFragment() ) {
targetFrag = "#" + targetTitleObj.getFragment();
}
this.targetFrag = targetFrag;
var targetNS = targetTitleObj.getNamespaceId();
if ( targetNS === 6 || targetNS === 14 ) {
this.targetLink = "[[:" + this.target + targetFrag + "]]";
} else {
this.targetLink = "[[" + this.target + targetFrag + "]]";
}
} else {
alert("Bad " + selected_result_label + "target: the title is invalid.");
this.errorID = "#closeXFD-resultContainer-target"; //error for invalid target
return;
}
}
if ( $('#closeXFD-rcatOptions-on').prop('checked') ) {
if ($("#closeXFD-result-redir-rcats").length !== 0) {
this.rcats = $('#closeXFD-result-redir-rcats').val();
} else {
this.rcats = "";
}
} else {
this.rcats = false;
}
}
//Make redirect; delete before redirect
if (selected_result_label == "redirect") {
this.makeRedirect = true;
this.delAndRedir = $('#closeXFD-redirectOption-deleteFirst').prop('checked');
}
//Rationale
this.rationale = $('#closeXFD-rationale').val();
//Punctuation after result
if ( $('#closeXFD-rationale-sentence').prop('checked') && this.rationale ) {
this.resultPunct = '';
} else {
this.resultPunct = '.';
}
//After
var selected_after = $('input[name="closeXFD-after"]:checked');
if (typeof $(selected_after).val() == "undefined") {
this.errorID = "#closeXFD-afterContainer"; //error in not choosing an "after" action
return;
}
this.after = $(selected_after).attr('id').slice(15);
//Options
if ( ($("#closeXFD-option-deletetalk").length !== 0) && ($("#closeXFD-option-deletetalk").is(":visible"))) {
this.deletetalk = !( $('#closeXFD-option-deletetalk').prop('checked') );
}
if ( ($("#closeXFD-option-deleteredir").length !== 0) && ($("#closeXFD-option-deleteredir").is(":visible"))) {
this.deleteredir = $('#closeXFD-option-deleteredir').prop('checked');
}
if ( ($("#closeXFD-option-unlinkbackl").length !== 0) && ($("#closeXFD-option-unlinkbackl").is(":visible"))) {
this.unlinkbackl = $('#closeXFD-option-unlinkbackl').prop('checked');
}
//Holding cell
if ( (($("#closeXFD-holdingcellsections").length !== 0) && ($("#closeXFD-holdingcellsections").is(":visible"))) || (($("#closeXFD-holdingcellsections-merge").length !== 0) && ($("#closeXFD-holdingcellsections-merge").is(":visible"))) ) {
var selected_holdingcell = $('input[name="closeXFD-holdingcell"]:checked');
if (typeof $(selected_holdingcell).val() == "undefined") { //error in not choosing a holding cell section
this.errorID = "#closeXFD-holdingcellsections";
if ($("#closeXFD-holdingcellsections-merge").is(":visible")) {
this.errorID += "-merge";
}
return;
}
this.holdingcell = $(selected_holdingcell).attr('id').slice(21);
}
};
// Function to unlink a link, or comment out a file, from a wikitext string. Returns the updated
// wikitext as a string, without checking if any changes have been made
// - derived from the Twinkle unlink module
// ( https://en.wikipedia.org/wiki/MediaWiki:Gadget-twinkleunlink.js ) and morebits.js library
// ( https://en.wikipedia.org/wiki/MediaWiki:Gadget-morebits.js )
XFDcloser.unlink = function (wikitext, unlinkThese, ns) {
// Remove image/file usages
if ( xfdSetting.xfd_type === "ffd" ) {
// Start building regex strings
normal_regex_str = "(";
gallery_regex_str = "(";
free_regex_str = "(";
for ( var i=0; i<unlinkThese.length; i++ ) {
// Take off namespace prefix
filename = unlinkThese[i].replace(/^.*?:/, "");
// For regex matching: first character can be either upper or lower case, special
// characters need to be escaped, spaces can be either spaces or underscores
filename_regex_str = "[" + mw.RegExp.escape(filename.slice(0, 1).toUpperCase()) +
mw.RegExp.escape(filename.slice(0, 1).toLowerCase()) + "]" +
mw.RegExp.escape(filename.slice(1)).replace(/ /g, "[ _]");
// Add to regex strings
normal_regex_str += "\\[\\[\\s*(?:[Ii]mage|[Ff]ile)\\s*:\\s*" + filename_regex_str +
"\\s*\\|?.*?(?:(?:\\[\\[.*?\\]\\]).*?)*\\]\\]";
gallery_regex_str += "^\\s*(?:[Ii]mage|[Ff]ile):\\s*" + filename_regex_str + ".*?$";
free_regex_str += "\\|\\s*(?:[\\w\\s]+\\=)?\\s*(?:(?:[Ii]mage|[Ff]ile):\\s*)?" +
filename_regex_str;
if ( i+1 === unlinkThese.length ) {
normal_regex_str += ")(?![^<]*?-->)";
gallery_regex_str += ")(?![^<]*?-->)";
free_regex_str += ")(?![^<]*?-->)";
} else {
normal_regex_str += "|";
gallery_regex_str += "|";
free_regex_str += "|";
}
}
// Check for normal file usage, i.e. [[File:Foobar.png|...]]
var normal_regex = new RegExp( normal_regex_str, "g");
wikitext = wikitext.replace(normal_regex, "");
// Check for gallery usage, i.e. instances that must start on a new line, eventually
// preceded with some space, and must include File: or Image: prefix
var gallery_regex = new RegExp( gallery_regex_str, "mg" );
wikitext = wikitext.replace(gallery_regex, "");
// Check for free usages, for example as template argument, might have the File: or Image:
// prefix excluded, but must be preceeded by an |
var free_regex = new RegExp( free_regex_str, "mg" );
wikitext = wikitext.replace(free_regex, "");
}
// Remove links
// Start building regex strings
var simple_regex_str = "\\[\\[:?(";
var named_regex_str = "\\[\\[:?(?:";
for ( var ii=0; ii<unlinkThese.length; ii++ ) {
// For regex matching: first character can be either upper or lower case, special
// characters need to be escaped, spaces can be either spaces or underscores
var unlink_regex_str = "[" + mw.RegExp.escape(unlinkThese[ii].slice(0, 1).toUpperCase()) +
mw.RegExp.escape(unlinkThese[ii].slice(0, 1).toLowerCase()) + "]" +
mw.RegExp.escape(unlinkThese[ii].slice(1)).replace(/ /g, "[ _]");
// Add to regex strings
simple_regex_str += unlink_regex_str;
named_regex_str += unlink_regex_str;
if ( ii+1 !== unlinkThese.length ) {
simple_regex_str += "|";
named_regex_str += "|";
}
}
simple_regex_str += ")(?:#[^\\|\\]]*?)?\\]\\](?![^<]*?-->)";
named_regex_str += ")(?:#[^\\|\\]]*?)?\\|([^\\[\\]\\n\\r]+?)\\]\\](?![^<]*?-->)";
var simple_regex = new RegExp( simple_regex_str, "g" );
var named_regex = new RegExp( named_regex_str, "g" );
//Set index articles for names, which should be treated like disambiguation pages, will contain
//one of these templates
var name_set_index_regex = /\{\{\s*(?:[Gg]iven[ _]name|[Ss]urnames?|[Nn]ickname|[Ff]irst[ _]name|[Ff]orename|[Dd]isambigN(?:ame|m)?)\s*(?:\|.*?)*?\}\}/g;
if ( ns === 10 ) {
//Within navbox templates, remove links entirely, including the preceding *'s and the following newline
var navbox_regex = new RegExp("\\{\\{[Nn]avbox(?: with collapsible groups| with columns)?\\s*\\|" +
"(?:.|\\n)*?(?:(?:\\{\\{" + // accounts for templates within the navbox
"(?:.|\\n)*?(?:(?:\\{\\{" + // accounts for templates within templates within the navbox
"(?:.|\\n)*?" +
"\\}\\})(?:.|\\n)*?)*?" +
"\\}\\})(?:.|\\n)*?)*" +
"\\}\\}", "g");
var navbox_simple_regex = new RegExp( "\\*+\\s+" + simple_regex_str + "[\\r\\t\\f\\v ]*\\n", "g" );
var navbox_named_regex = new RegExp( "\\*+\\s+" + named_regex_str + "[\\r\\t\\f\\v ]*\\n", "g" );
//Find navbox templates
var navboxes = wikitext.match(navbox_regex);
if ( navboxes ) {
// remove regex matches from wikitext
for ( var jj=0; jj<navboxes.length; jj++ ) {
replacement = navboxes[jj].replace(navbox_simple_regex, "").replace(navbox_named_regex, "");
wikitext = wikitext.replace(navboxes[jj], replacement);
}
}
} else if ( ns === -7 || ( ns === 0 && name_set_index_regex.test(wikitext) ) ) {
//For disambiguation pages, entirely remove list items containing a backlink, including the
//preceding *'s and the following newline (but skiping list items with multiple links)
var dab_simple_regex = new RegExp( "\\*+[^\\[\\]\\n\\r]*" + simple_regex_str + "[^\\[\\]\\n\\r]*\\n", "g" );
var dab_named_regex = new RegExp( "\\*+[^\\[\\]\\n\\r]*" + named_regex_str + "[^\\[\\]\\n\\r]*\\n", "g" );
wikitext = wikitext.replace(dab_simple_regex, "").replace(dab_named_regex, "");
} else {
//For See also sections, entirely remove list items containing a backlink, including the
//preceding *'s and the following newline (but skiping list items with multiple links)
var seealso_regex = /==+\s*[Ss]ee [Aa]lso\s*==+\n+(?:^.*\n*)*?(?:(?===+)|$)/gm;
var seealso_simple_regex = new RegExp( "\\*+[^\\[\\]\\n\\r]*" + simple_regex_str + "[^\\[\\]\\n\\r]*\\n", "g" );
var seealso_named_regex = new RegExp( "\\*+[^\\[\\]\\n\\r]*" + named_regex_str + "[^\\[\\]\\n\\r]*\\n", "g" );
var seealso = wikitext.match(seealso_regex);
if ( seealso ) {
// remove regex matches from wikitext
for ( var kk=0; kk<seealso.length; kk++ ) {
replacement = (seealso[kk]+"\n").replace(seealso_simple_regex, "").replace(seealso_named_regex, "");
wikitext = wikitext.replace(seealso[kk].trim(), replacement.trim());
}
}
}
wikitext = wikitext.replace(simple_regex, "$1").replace(named_regex, "$1");
return wikitext;
};
/* == Closing-related functions == */
/* ********************************* */
//TASKS (all possible tasks listed here, but only a subset to be done for any particular close):
//0: Close section on nomination page
//1: IF doKeepActions OR doMergeActions, add old xfd template to each talk page
//2: IF doKeepActions, remove nomination template from each nominated page
//3: IF doMergeActions AND NOT tfd, replace nom template with merge template for each nom page,
// and add merge tag to target's talk page
//4: IF doDeletion, delete nominated page
//5: IF tagSpeedy, tag nominated page for speedy deletion
//6: IF holdingCell OR ( doMergeActions AND tfd ), replace nomination template with
// being deleted template, or with speedy-del if 'ready for deletion'
//7: IF holdingCell OR ( doMergeActions AND tfd ), list at holding cell
//8: IF deletetalk, delete talk pages
//9: IF tagTalkSpeedy, tag talk pages for speedy deletion
//10: IF deleteredir, find and delete redirects
//11: IF unlinkbackl, notify which pages are to have links unlinked - if confirmed, unlink them
//12: IF doRedirectActions AND NOT delAndRedir, redirect each nominated page to target
//13: IF doRedirectActions AND delAndRedir, delete each nom page and then redirect it to target
//14: IF doRedirectActions, remove circular links from target
//FORLATER: When getting section content, use rvsection= parameter in the api call
//Define all task functions, and then can start processing the close
XFDcloser.doTask = new Array(12);
// --- Task 0: Close section on nomination page --- //
XFDcloser.doTask[0] = function(nom_data, input_data, next_tasks) {
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "0");
// Make top and bottom wikitext
var to_target = "";
if ( input_data.target ) {
to_target = " to " + input_data.targetLink;
}
var xfd_close_top = xfdSetting.wikitext.closeTop
.replace(/__RESULT__/, input_data.result)
.replace(/__TO_TARGET__/, to_target)
.replace(/__RPUNCT__/, input_data.resultPunct)
.replace(/__RATIONALE__/, input_data.rationale)
.replace(/__SIG__/, xfdc.sig);
var xfd_close_editsum = "/* " + nom_data.section_header + " */ Closed " +
"as " + input_data.result + xfdc.script_advert;
// Callback functions for processing api failures
apiFailedCallback_editNomPage = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "0", "edit page " +
XFDcloser.makeLink(nom_data.nom_page) + "; could not close discussion", code, result );
};
apiFailedCallback_getNomPage = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "0", "read contents of page " +
XFDcloser.makeLink(nom_data.nom_page) + "; could not close discussion", code, result );
};
// Function to edit with the api
apiEditNomPage = function (new_section_text) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: nom_data.nom_page,
section: nom_data.editsection,
text: new_section_text,
summary: xfd_close_editsum
} ).done( function() {
XFDcloser.taskFinished(nom_data.close_span_id, "0");
XFDcloser.doPostCloseTasks(nom_data, input_data, next_tasks);
} ).fail( apiFailedCallback_editNomPage );
};
// Callback functions for processing api results
apiCallback_getNomPage = function (result) {
var p_id = result.query.pageids;
var p_contents = result.query.pages[ p_id ].revisions[ 0 ][ '*' ];
if ( p_contents.includes(xfdSetting.wikitext.alreadyClosed) ) {
XFDcloser.abortTasks(nom_data.close_span_id, next_tasks);
return;
}
var section_heading = p_contents.slice(0, p_contents.indexOf("\n"));
var section_contents = p_contents.slice(p_contents.indexOf("\n")+1)
.replace(/({{closing}}|{{AfDh}}|{{AfDb}}|\{\{REMOVE THIS TEMPLATE WHEN CLOSING THIS AfD\|.?\}\}|<noinclude>\[\[Category:Relisted AfD debates\|.*?\]\]<\/noinclude>)/gi, "");
var updated_section = "";
if ( xfdSetting.xfd_type === "afd" || xfdSetting.xfd_type === "mfd" ) {
updated_section = xfd_close_top + "\n" + section_heading + "\n" +
section_contents.trim() + "\n" + xfdSetting.wikitext.closeBottom;
} else {
updated_section = section_heading + "\n" + xfd_close_top + "\n" +
section_contents.trim() + "\n" + xfdSetting.wikitext.closeBottom;
}
// Perform edit to close XFD discussion
apiEditNomPage(updated_section);
};
// Get nomination page content and remove {Closing} etc templates if present
new mw.Api().get( {
action: 'query',
titles: nom_data.nom_page,
prop: 'revisions',
rvprop: 'content',
rvsection: nom_data.editsection,
indexpageids: 1
} ).done( apiCallback_getNomPage )
.fail( apiFailedCallback_getNomPage );
};
// --- Task 1: Add old xfd template to each talk page --- //
XFDcloser.doTask[1] = function(nom_data, input_data) {
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "1");
var edits_made = 0; // var to be incremented after each edit
var editsum = "Old " + xfdSetting.xfd_type.toUpperCase() + " – " + nom_data.nom_date +
": " + input_data.result + xfdc.script_advert;
// - - - Common functions - - - //
// Callback function for processing api failures
apiFailedCallback_editTalk = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "1", "edit talk page(s)", code, result);
};
// Function to make an edit with the api - prepending content
apiEditTalk = function (pagetitle) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: pagetitle,
prependtext: oldxfd_wikitext,
summary: editsum
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "1");
}
}).fail( apiFailedCallback_editTalk );
};
apiEditTalk_append = function (pagetitle) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: pagetitle,
appendtext: '\n' + oldxfd_wikitext,
summary: editsum
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "1");
}
}).fail( apiFailedCallback_editTalk );
};
// Function to make an edit with the api to the redirect's target - prepending content
apiEditTalkRedirTarget = function (pagetitle, prepend_content) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: pagetitle,
prependtext: prepend_content,
summary: editsum,
redirect: 1
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "1");
}
}).fail( apiFailedCallback_editTalk );
};
// Function to make an edit with the api - replacing content
apiEditTalk_replace = function (pagetitle, replacementtext) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: pagetitle,
text: replacementtext,
summary: editsum
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "1");
}
}).fail( apiFailedCallback_editTalk );
};
if ( xfdSetting.xfd_type === "afd" ) {
// - - - Task 1 (AFD) - - - //
//Parts of this task derived from https://en.wikipedia.org/wiki/User:Mr.Z-man/closeAFD2.js
// Functions to be used inside callback functions
makeNewWikitext = function(wikitext) {
var oldafdpatt = /\n?\{\{(old|afd) ?(old|afd) ?(multi|full)?((.|\n)*?)\}\}\n?/i;
var numtest = /[A-z]+([0-9])/i;
var oldafdmulti = "{{Old AfD multi";
old = oldafdpatt.exec(wikitext);
var count = 0;
if ( old ) {
count = 1;
var parts = old[4].split("|");
var params = {};
for ( var i=0; i<parts.length; i++ ) {
if ( !parts[i].trim() ) {
continue;
}
pieces = parts[i].split("=");
params[pieces[0].trim()] = pieces[1].trim();
var num = numtest.exec(pieces[0].trim());
if (num) {
res = parseInt(num[1]);
if (res > count) {
count = res;
}
}
}
for (var p in params) {
oldafdmulti += " |"+p+"="+params[p];
}
}
count++;
c = count.toString();
if (count == 1) {
c = '';
}
var debate = nom_data.nom_page.replace(xfdSetting.subpagePath, "");
oldafdmulti += " |date" + c + "=" + nom_data.nom_date +
" |result" + c + "='''" + input_data.result + "'''" +
" |page" + c + "=" + debate + '}}';
if ( count > 1 ) {
newtext = wikitext.replace(oldafdpatt, "\n"+oldafdmulti+"\n");
} else { // [[WP:Talk page layout]] is too complicated to automate, so don't try
newtext = oldafdmulti+'\n'+wikitext;
}
return newtext;
};
// Callback function for processing api failure
apiFailedCallback_getTalkPage = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "1", "read contents of talk page(s)", code, result);
};
// Callback function for processing api results
apiCallback_getTalkPage = function (result) {
//Get old wikitext, or set to empty string if page doesn't exist (page id is negative)
var oldwikitext = "";
var page_ids = result.query.pageids;
for (var i = 0; i < page_ids.length; i++) {
var p_title = result.query.pages[ page_ids[i] ].title;
if (parseInt(page_ids[i]) > 0) {
oldwikitext = result.query.pages[ page_ids[i] ].revisions[ 0 ][ '*' ];
} else {
oldwikitext = "";
}
// Check namespace and that subject page exists
j = nom_data.talkPages.indexOf(p_title);
if ( j === -1 ) {
XFDcloser.taskError(nom_data.close_span_id, "1", "API: query result included " +
"unexpected talk page title \"" + XFDcloser.makeLink(title) + "\"; " +
"this talk page will not be edited");
} else if ( !nom_data.pageExists[j] ) {
XFDcloser.taskError(nom_data.close_span_id, "1", "The subject page for \"" +
XFDcloser.makeLink(p_title) + "\" does not exist; this talk page will not be edited");
} else {
apiEditTalk_replace(p_title, makeNewWikitext(oldwikitext));
}
}
};
//get talk page wikitext through api
new mw.Api().get( {
action: 'query',
titles: nom_data.talkPages.join("|"),
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ) .done( apiCallback_getTalkPage )
.fail( apiFailedCallback_getTalkPage );
} else {
// - - - Task 1 (RFD, MFD) - - - //
oldxfd_wikitext = xfdSetting.wikitext.oldXfd
.replace(/__DATE__/, nom_data.nom_date)
.replace(/__SECTION__/, nom_data.section_header)
.replace(/__RESULT__/, input_data.result)
.replace(/__FIRSTDATE__/, nom_data.first_date)
.replace(/__SUBPAGE__/, nom_data.nom_page.replace(xfdSetting.subpagePath, ""));
//API callbacks
apiFailedCallback_getTalkRedirectInfo = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "1", "read contents of talk page(s)", code, result);
};
apiCallback_getTalkRedirectInfo = function (result) {
//Check if each page is a redirect
var page_ids = result.query.pageids;
//count adjustment, needed in case any empty strings were filtered out
var edits_made = nom_data.pages.length - page_ids.length;
for (var i = 0; i < page_ids.length; i++) {
var talktitle = result.query.pages[ page_ids[i] ].title;
if ( result.query.pages[ page_ids[i] ].redirect === "" ) {
// Is a redirect...
if ( xfdSetting.xfd_type === "rfd" ) {
// for RFD, ask what to do
var response = confirm("\"" + talktitle + "\" is currently a redirect. Okay " +
"to replace with Old " + xfdSetting.xfd_type.toUpperCase() + " template?");
if ( response ) {
// Make the edit, replacing previous content
apiEditTalk_replace(talktitle, oldxfd_wikitext);
} else {
// Skip
XFDcloser.taskWarning(nom_data.close_span_id, "1", "\"" + talktitle + "\" skipped");
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "1");
}
}
} else if ( xfdSetting.xfd_type === "mfd" ) {
// For MFD, edit edirect target & use altpage parameter
var altpage = XFDcloser.getSubjectPage(talktitle);
apiEditTalkRedirTarget(talktitle, oldxfd_wikitext.replace("}}", " |altpage="+altpage+"}}"));
} else {
// For other venues, append rather than prepend the template
apiEditTalk_append(talktitle);
}
} else {
// Not a redirect - just make the edit
apiEditTalk(talktitle);
}
}
};
//Make a filtered list of talkpages which will be checked for redirect status
var filtered_talkpages = "";
if ( xfdSetting.xfd_type === "rfd" || xfdSetting.xfd_type === "mfd" ) {
// Filter out empty strings from talk page array (i.e. nominated pages which are themselves talkpages)
filtered_talkpages = nom_data.talkPages.join("|").replace(/\|+/g, "|").replace(/^\||\|$/g, "");
} else {
// For each talk page, check subject page exists
for (ii = 0; ii < nom_data.pages.length; ii++) {
if ( !nom_data.pageExists[ii] ) {
XFDcloser.taskError(nom_data.close_span_id, "1", "\"" + XFDcloser.makeLink(nom_data.pages[ii]) +
"\" does not exist; its talk page will not be edited");
} else if ( filtered_talkpages === "" ) {
filtered_talkpages = nom_data.talkPages[ii];
} else {
filtered_talkpages += "|" + nom_data.talkPages[ii];
}
}
}
if ( filtered_talkpages === "" ) {
// nothing to do
XFDcloser.taskFinished(nom_data.close_span_id, "1");
XFDcloser.taskWarning(nom_data.close_span_id, "1", "none found");
} else {
// get talk page redirect status from api
new mw.Api().get( {
action: 'query',
prop: 'info',
titles: filtered_talkpages,
indexpageids: 1
} ).done( apiCallback_getTalkRedirectInfo )
.fail( apiFailedCallback_getTalkRedirectInfo );
}
}
};
// --- Task 2: Remove nom template from nominated pages (and then prepend text if specified) --- //
XFDcloser.doTask[2] = function(nom_data, input_data, prepend_wikitext, task_number) {
// Default values if params are not defined
if ( prepend_wikitext == null ) {
prepend_wikitext = "";
}
if ( task_number == null ) {
task_number = "2";
// Notify task 2 is started
XFDcloser.taskStarted(nom_data.close_span_id, task_number);
}
var editsum = xfdSetting.xfd_type.toUpperCase() + " closed as " +
input_data.result + xfdc.script_advert;
var edits_made = 0; // var to be incremented after each edit
// Callback functions for processing api failures
apiFailedCallback_editPages = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, task_number, "edit nominated "+
"page(s)", code, result);
};
apiFailedCallback_getPages = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, task_number, "read contents of "+
"nominated page(s)", code, result);
};
// Function to edit each nominated page with the api
apiEditPages = function (pagetitle, new_section_text) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: pagetitle,
text: new_section_text,
summary: editsum
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, task_number);
}
} ).fail( apiFailedCallback_editNomPage );
};
// Callback function for processing api results
apiCallback_getPages = function (result) {
//Get old wikitext, or make error if page doesn't exist, or if page is in wrong namespace
var oldwikitext = "";
var page_ids = result.query.pageids;
for (var i = 0; i < page_ids.length; i++) {
var p_title = result.query.pages[ page_ids[i] ].title;
// Check that subject page exists
j = nom_data.pages.indexOf(p_title);
if ( j === -1 ) {
XFDcloser.taskError(nom_data.close_span_id, "2", "API: query result included " +
"unexpected page title \"" + XFDcloser.makeLink(p_title) + "\"; this page will not be edited");
} else if ( parseInt(page_ids[i]) < 0 ) { //more recent info than nom_data.pageExists[j]
XFDcloser.taskError(nom_data.close_span_id, "2", "The page \"" +
XFDcloser.makeLink(p_title) + "\" does not exist, and will not be edited");
} else {
oldwikitext = result.query.pages[ page_ids[i] ].revisions[ 0 ][ '*' ];
if ( nom_data.pages[j] === input_data.target ) {
// Don't prepend anything to redirect target page - just remove nom template
updated_wikitext = oldwikitext.replace(xfdSetting.regex.nomTemplate, "");
} else {
updated_wikitext = prepend_wikitext +
oldwikitext.replace(xfdSetting.regex.nomTemplate, "");
}
//Warn if no changes made
if ( updated_wikitext === oldwikitext || updated_wikitext === prepend_wikitext + oldwikitext ) {
XFDcloser.taskWarning(nom_data.close_span_id, "2", "Warning: " +
"nomination template not found on page \"" + XFDcloser.makeLink(p_title) + "\"");
}
apiEditPages(p_title, updated_wikitext);
}
}
};
//get each page's wikitext through api
new mw.Api().get( {
action: 'query',
titles: nom_data.pages.join("|"),
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ) .done( apiCallback_getPages )
.fail( apiFailedCallback_getPages );
};
// --- Task 3: Replace nomination template with merge template for each nominated page --- //
// Task only for AFDs and MFDs. All CFDs are basic closes, 'merge' isn't a likely
// outcome for FFDs/RFDs (but could still be closed as such via Custom result), and
// TFDs use {Being deleted} and the holding cell.
XFDcloser.doTask[3] = function(nom_data, input_data) {
//Parts of this function derived from https://en.wikipedia.org/wiki/User:Mr.Z-man/closeAFD2.js
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "3");
// Add 'merge from' template to target's talk page,
var merge_editsum = "[[" + nom_data.disc_link + "]] closed as " +
input_data.result + xfdc.script_advert;
var target_talk = XFDcloser.getTalkPage(input_data.target);
if ( target_talk === "" ) {
//If target is itself a talkpage, use the target
target_talk = input_data.target;
}
var today = new Date();
var curdate = today.getUTCDate().toString() + " " + xfdc.monthnames[today.getUTCMonth()] +
" " + today.getUTCFullYear().toString();
var debate = nom_data.nom_page.replace(xfdSetting.subpagePath, "");
var mergefrom_wikitext = "";
for (var i=0; i<nom_data.pages.length; i++) {
mergefrom_wikitext+= xfdSetting.wikitext.mergeFrom
.replace(/__NOMINATED__/, nom_data.pages[i])
.replace(/__DEBATE__/, debate)
.replace(/__DATE__/, curdate);
}
var mergeto_wikitext = xfdSetting.wikitext.mergeTo
.replace(/__TARGET__/, input_data.target)
.replace(/__DEBATE__/, debate)
.replace(/__DATE__/, curdate)
.replace(/__TARGETTALK__/, target_talk); //for MFDs
// Callback function for processing api failures
apiFailedCallback_editTargetTalk = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "3", "edit merge target talk page \"" +
XFDcloser.makeLink(target_talk) + "\"", code, result );
// still try to replace nom template(s) with 'merge to' template(s) using XFDcloser.doTask[2]
XFDcloser.doTask[2](nom_data, input_data, mergeto_wikitext, "3");
};
// function to edit target talk page
editTargetTalk = function() {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: target_talk,
prependtext: mergefrom_wikitext,
summary: merge_editsum
} ).done( function() {
// now replace nom template(s) with 'merge to' template(s) using XFDcloser.doTask[2]
XFDcloser.doTask[2](nom_data, input_data, mergeto_wikitext, "3");
}).fail( apiFailedCallback_editTargetTalk );
};
// Check if the target is one of the nominated pages
var j = nom_data.pages.indexOf(input_data.target);
if ( j !== -1 ) {
// No need to add merge from template - this was a nominated page, and will have an old xfd
// template put on its talkpage specify the merge result
// So just replace nom template(s) with 'merge to' template(s) using XFDcloser.doTask[2]
XFDcloser.doTask[2](nom_data, input_data, mergeto_wikitext, "3");
} else {
editTargetTalk();
}
};
// --- Task 4: Delete nominated pages --- //
XFDcloser.doTask[4] = function(nom_data) { //input_data not needed
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "4");
var del_count = 0; // var to be incremented after each deletion.
// Reason for deletion log
var del_reason = "[[" + nom_data.disc_link + "]]" + xfdc.script_advert;
// Callback functions for processing api failures
apiFailedCallback_deletePages = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "4", "delete page(s)", code, result );
};
//Function to delete with the api
apiDeletePage = function(pagetitle) {
new mw.Api().postWithToken( 'csrf', {
action: 'delete',
title: pagetitle,
reason: del_reason,
} ).done( function() {
del_count++;
if (del_count === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "4");
}
} ).fail( apiFailedCallback_deletePages );
};
// For each page, check it exists, then delete with api
for (var i=0; i < nom_data.pages.length; i++) {
if ( !nom_data.pageExists[i] ) {
//page already doesn't exist, presumbaly already deleted - don't try to delete it again
XFDcloser.taskWarning(nom_data.close_span_id, "4", "\"" + XFDcloser.makeLink(nom_data.pages[i]) +
"\" skipped: does not exist (may have already been deleted by others)");
del_count++;
if (del_count === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "4");
}
} else {
apiDeletePage(nom_data.pages[i]);
}
}
};
// --- Task 5: tagWithSpeedy --- //
XFDcloser.doTask[5] = function(nom_data) { //input_data not needed
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "5");
var edits_made = 0; // var to be incremented after each edit.
var speedy_tag_editsum = "[[WP:G6|G6]] Speedy deletion nomination, per [[" +
nom_data.disc_link + "]]" + xfdc.script_advert;
var speedy_tag_wikitext = "{"+"{Db-xfd|fullvotepage=" + nom_data.disc_link + "}"+"}\n";
// Callback functions for processing api failures
apiFailedCallback_tagSpeedy = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "5", "tag page(s) for " +
"speedy deletion", code, result );
};
apiEditTagSpeedy = function (page_title) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: page_title,
prependtext: speedy_tag_wikitext,
summary: speedy_tag_editsum,
nocreate: true
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "5");
}
} ).fail( apiFailedCallback_tagSpeedy );
};
// For each page, check it exists, then tag for deletion
for (var i=0; i < nom_data.pages.length; i++) {
//Check namespace
if ( !nom_data.pageExists[i] ) {
XFDcloser.taskWarning(nom_data.close_span_id, "5", "\"" +
XFDcloser.makeLink(nom_data.talkPages[i]) + "\" skipped: does not exist]");
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "5");
}
} else {
apiEditTagSpeedy(nom_data.pages[i]);
}
}
};
// --- Task 6: add Being deleted ---
// TFD only
XFDcloser.doTask[6] = function(nom_data, input_data) {
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "6");
var editsum = ""; // will set later
var replacement_wikitext = ""; // will set later
var edits_made = 0; // var to be incremented after each edit.
var merge_wikitext = "";
if (input_data.target) {
merge_wikitext = "|merge=" + input_data.target;
}
if ( input_data.holdingcell === "ready" ) {
editsum = "[[WP:G6|G6]] Speedy deletion nomination, per [[" + nom_data.disc_link +
"]]" + xfdc.script_advert;
replacement_wikitext = "{" + "{Db-xfd|fullvotepage=" + nom_data.disc_link + "}" + "}";
} else {
editsum = "Per [[" + nom_data.disc_link + "]], added {" + "{being deleted}" +"}" +
xfdc.script_advert;
replacement_wikitext = "{" + "{Being deleted|" + nom_data.nom_date + "|" +
mw.util.wikiUrlencode(nom_data.section_header) + merge_wikitext + "}" + "}";
}
// Callback functions for processing api failures
apiFailedCallback_editTemplate = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "6", "edit template(s)", code, result );
};
apiFailedCallback_getTemplates = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "6", "read contents of " +
"nominated page(s)", code, result );
};
//Function to make the edit
apiEditTemplate = function(tempalte_title, new_content, es) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: tempalte_title,
text: new_content,
summary: es
} ).done( function() {
edits_made++;
if (edits_made === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "6");
}
} ).fail( apiFailedCallback_editTemplate );
};
// Callback functions for processing api result
apiCallback_getTemplates = function (result) {
var page_ids = result.query.pageids;
for (var i = 0; i < page_ids.length; i++) {
var t_contents = "";
var t_title = result.query.pages[ page_ids[i] ].title;
var j = nom_data.pages.indexOf(t_title);
if ( j === -1 ) {
XFDcloser.taskError(nom_data.close_span_id, "6", "API: query result included " +
"unexpected page title \"" + XFDcloser.makeLink(t_title) + "\"; " +
"this page will not be edited");
} else if (parseInt(page_ids[i]) < 0) {
XFDcloser.taskError(nom_data.close_span_id, "6", "\"" + XFDcloser.makeLink(t_title) + "\" " +
"does not seem to exist (may have been deleted)");
} else {
// Replace {Template for discussion/dated} or {Tfm/dated} (which
// may or may not be noincluded) with noincluded {Being deleted}
t_contents = result.query.pages[ page_ids[i] ].revisions[ 0 ][ '*' ];
var updated_content = "";
var e_s = "";
//If this is the merge target, don't add Being deleted - just remove nom template
if ( input_data.target && t_title===input_data.target ) {
updated_content = t_contents.replace(xfdSetting.regex.nomTemplate, "");
e_s = "[[" + nom_data.disc_link + "]] closed as " +
input_data.result + xfdc.script_advert;
} else {
e_s = editsum;
if ( t_contents.search(xfdSetting.regex.nomTemplate) < 0 ) {
updated_content = "<no" + "include>" + replacement_wikitext +
"</no" + "include>" + t_contents;
} else {
updated_content = t_contents.replace(xfdSetting.regex.nomTemplate, "<no" + "include>" + replacement_wikitext + "</no" + "include>");
}
}
apiEditTemplate(t_title, updated_content, e_s);
}
}
};
//get page wikitext through api
new mw.Api().get( {
action: 'query',
titles: nom_data.pages.join("|"),
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getTemplates )
.fail( apiFailedCallback_getTemplates );
};
// --- Task 7: Add to Holding cell --- //
// TFD only
XFDcloser.doTask[7] = function(nom_data, input_data) {
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "7");
//get holding cell section number for editing
var holdingCellSectionNumbers = {
"review": 2,
"convert": 11,
"substitute": 12,
"orphan": 13,
"ready": 14, // (ready for deletion)
"merge-arts": 4,
"merge-geopolgov": 5, // (geography, politics and governance)
"merge-religion": 6,
"merge-sports": 7,
"merge-trasnport": 8,
"merge-other": 9,
"merge-meta": 10
};
var holdCellSection = holdingCellSectionNumbers[input_data.holdingcell];
//Build up wikitext to append to holding cell section
var delete_param = "";
if ( holdCellSection === 14 ) { // 14 is "Ready for deletion"
delete_param = "|delete=1";
}
var section_param = "";
if (nom_data.pages.length>1 || nom_data.pages[0]!==nom_data.section_header) {
section_param = "|section=" + nom_data.section_header;
}
var wikitext_append = "";
for (i = 0; i < nom_data.pages.length; i++) {
//Check existance and namespace
if ( !nom_data.correctNS[i] ) {
XFDcloser.taskError(nom_data.close_span_id, "7", "\"" + XFDcloser.makeLink(nom_data.pages[i]) + "\" is " +
"not in the " + xfdc.namespaces[xfdSetting.ns_number.toString()] + " namespace, " +
"and will not be listed at the holding cell");
} else if ( !nom_data.pageExists[i] ) {
XFDcloser.taskWarning(nom_data.close_span_id, "7", "\"" +
XFDcloser.makeLink(nom_data.talkPages[i]) + "\" does not exist, and will not be listed at the holding cell");
} else {
wikitext_append += "*{" + "{tfdl|" + nom_data.pages[i].slice(9) +
"|" + nom_data.nom_date + section_param + delete_param + "}}\n";
}
}
if ( wikitext_append === "" ) {
//If all don't exist or are in wrong namespace, then there's nothing to do
return;
}
var editsum = "Listing template(s) per [[" + nom_data.disc_link + "]]" + xfdc.script_advert;
var holdingcellpagetitle = xfdSetting.path.slice(0,-4) + "Holding cell";
// Callback functions for processing api failures
apiFailedCallback_getHoldCell = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "7", "read contents of \"" +
XFDcloser.makeLink(holdingcellpagetitle) + "\"; could not add templates to holding cell", code, result );
};
apiFailedCallback_editHoldCell = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "7", "edit \"" +
XFDcloser.makeLink(holdingcellpagetitle), code, result );
};
//Function to make an edit
apiEditHoldingCell = function(updated_section_wikitext) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: holdingcellpagetitle,
section: holdCellSection,
text: updated_section_wikitext,
summary: editsum
} ).done( function() {
XFDcloser.taskFinished(nom_data.close_span_id, "7");
} ).fail( apiFailedCallback_editHoldCell );
};
// Callback function for processing api results
apiCallback_getHoldCell = function (result) {
var p_id = result.query.pageids;
//get page contents, make all headings level 3 so sections can be counted
var p_contents = result.query.pages[ p_id ].revisions[ 0 ][ '*' ].replace(/====/gi, "===");
var sections_array = p_contents.split("===");
var section_heading = sections_array[(holdCellSection*2-1)];
var section_contents = sections_array[(holdCellSection*2)];
//remove "* ''None currently''" except if inside a <!--html comment-->
section_contents = section_contents.replace(/\n*^\*\s*''None currently''\s*$(?![^<]*?-->)/gim, "");
var heading_level = "===";
if ( (4 <= holdCellSection) && ( holdCellSection <= 10) ) { //Merge subsections
heading_level = "====";
}
var updated_section = heading_level + section_heading + heading_level + "\n" +
section_contents.trim() + "\n" + wikitext_append;
apiEditHoldingCell(updated_section);
};
//get holding cell contents
new mw.Api().get( {
action: 'query',
titles: holdingcellpagetitle,
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getHoldCell )
.fail( apiFailedCallback_getHoldCell );
};
// --- Task 8: deleteTalk --- //
XFDcloser.doTask[8] = function(nom_data) { //input_data not needed
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "8");
var del_count = 0; // var to be incremented after each deletion
var skip_count = 0;
// Reason for deletion log
var delTalk_reason = "[[WP:CSD#G8|G8]]: Talk page of deleted page." + xfdc.script_advert;
// Callback functions for processing api failures
apiFailedCallback_deletePages = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "8", "delete talk page(s)", code, result );
};
//Function to delete with the api
apiDeleteTalk = function(pagetitle) {
new mw.Api().postWithToken( 'csrf', {
action: 'delete',
title: pagetitle,
reason: delTalk_reason,
} ).done( function() {
del_count++;
if ( del_count === nom_data.talkPages.length ) {
XFDcloser.taskFinished(nom_data.close_span_id, "8");
}
} ).fail( apiFailedCallback_deletePages );
};
//For each talk page, check namespace, and that it exists, then delete it
for (var i=0; i < nom_data.talkPages.length; i++) {
if ( nom_data.talkPages[i] === "" ) {
// The nominated page is itself a talkpage (MfD/RfD) - skip
del_count++;
skip_count++;
if ( del_count === nom_data.talkPages.length ) {
XFDcloser.taskFinished(nom_data.close_span_id, "8");
if ( skip_count === del_count ) {
XFDcloser.taskWarning(nom_data.close_span_id, "8", "none found");
}
}
} else if ( !nom_data.talkExists[i] ) {
// Talk page already doesn't exist, either it was already deleted or was never created -
// don't try to delete it again.
XFDcloser.taskWarning(nom_data.close_span_id, "8", "\"" +
XFDcloser.makeLink(nom_data.talkPages[i]) + "\" skipped: does not exist");
del_count++;
if ( del_count === nom_data.talkPages.length ) {
XFDcloser.taskFinished(nom_data.close_span_id, "8");
}
} else {
apiDeleteTalk(nom_data.talkPages[i]);
}
}
};
// --- Task 9: tagTalkWithSpeedy --- //
XFDcloser.doTask[9] = function(nom_data) { //input_data not needed
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "9");
var edits_made = 0; // var to be incremented after each edit
var skip_count = 0;
// Reason for edit summary
var speedy_tag_editsum = "[[WP:G8|G8]] Speedy deletion nomination, per [[" +
nom_data.disc_link + "]]" + xfdc.script_advert;
var speedy_tag_wikitext = "{"+"{Db-talk}"+"}\n";
// Callback functions for processing api failures
apiFailedCallback_tagTalkSpeedy = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "9", "tag talk page(s) for " +
"speedy deletion", code, result );
};
apiEditTagTalkSpeedy = function (page_title) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: page_title,
prependtext: speedy_tag_wikitext,
summary: speedy_tag_editsum
} ).done( function() {
edits_made++;
if ( edits_made === nom_data.talkPages.length ) {
XFDcloser.taskFinished(nom_data.close_span_id, "9");
}
} ).fail( apiFailedCallback_tagTalkSpeedy );
};
//For each talk page, check that it exists, then tag it
for (var i=0; i < nom_data.talkPages.length; i++) {
if ( nom_data.talkPages[i] === "" ) {
// The nominated page is itself a talkpage (MfD/RfD) - skip
edits_made++;
skip_count++;
if ( edits_made === nom_data.talkPages.length ) {
XFDcloser.taskFinished(nom_data.close_span_id, "8");
if ( skip_count === edits_made ) {
XFDcloser.taskWarning(nom_data.close_span_id, "8", "none found");
}
}
} else if ( !nom_data.talkExists[i] ) {
// Talk page already doesn't exist, either it was already deleted or was never created -
// don't try to delete it again.
XFDcloser.taskWarning(nom_data.close_span_id, "9", "\"" +
XFDcloser.makeLink(nom_data.talkPages[i]) + "\" skipped: does not exist");
edits_made++;
if ( edits_made === nom_data.talkPages.length ) {
XFDcloser.taskFinished(nom_data.close_span_id, "9");
}
} else {
apiEditTagTalkSpeedy(nom_data.talkPages[i]);
}
}
};
// --- Task 10: deleteRedirects --- //
XFDcloser.doTask[10] = function(nom_data, input_data) {
// Notify task(s) started
XFDcloser.taskStarted(nom_data.close_span_id, "10");
if ( input_data.deletetalk ) {
XFDcloser.taskStarted(nom_data.close_span_id, "15");
}
// Finding redirect(s) to delete
var nomtitles = nom_data.pages.join("|");
// Arrays to be filled in later
var redirect_titles = [];
var redirect_talk_titles = [];
var redirect_talk_ids = [];
// var to increment with each deletion
var delr_count = 0;
var delrt_count = 0;
var delrt_skip = 0;
// Reason for deletion log
var delr_reason = "Delete redirect: [[" + nom_data.disc_link + "]] closed as " +
input_data.result + xfdc.script_advert;
var delrt_reason = "[[WP:CSD#G8|G8]]: Talk page of deleted page." + xfdc.script_advert;
// Callback functions for processing api failures
apiFailedCallback_getRedirects = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "10", "get redirects", code, result);
};
apiFailedCallback_deleteRedir = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "10", "delete redirect(s)", code, result);
};
apiFailedCallback_getRedirectTalks = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "15", "get redirects' talk pages", code, result);
};
apiFailedCallback_deleteRedirTalk = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "15", "delete redirects' talk pages", code, result);
};
// Function to delete a redirect
apiDeleteRedir = function(pagetitle) {
new mw.Api().postWithToken( 'csrf', {
action: 'delete',
title: pagetitle,
reason: delr_reason
} ).done( function() {
delr_count++;
if (delr_count === redirect_titles.length) {
// All done
XFDcloser.taskFinished(nom_data.close_span_id, "10");
}
} ).fail( apiFailedCallback_deleteRedir );
};
// Function to delete a redirect talkpage
apiDeleteRedirTalk = function(talkpage_id) {
new mw.Api().postWithToken( 'csrf', {
action: 'delete',
pageid: talkpage_id,
reason: delrt_reason
} ).done( function() {
delrt_count++;
if ( delrt_count + delrt_skip === redirect_talk_ids.length ) {
// All done
XFDcloser.taskFinished(nom_data.close_span_id, "15");
}
} ).fail( apiFailedCallback_deleteRedirTalk );
};
// Callback functions for processing api results
apiCallback_getRedirectTalks = function(result) {
if ( result.query.pageids ) {
redirect_talk_ids = redirect_talk_ids.concat(result.query.pageids);
}
if ( redirect_talk_ids.length === redirect_talk_titles.length ) {
// All done - start deleting
if ( redirect_talk_ids.length === 0 ) {
// No pages to delete
XFDcloser.taskFinished(nom_data.close_span_id, "15");
XFDcloser.taskWarning(nom_data.close_span_id, "15", "none found");
} else {
for (var jj=0; jj<redirect_talk_ids.length; jj++) {
if ( redirect_talk_ids[jj] > 0 ) {
// Page exists: delete it
apiDeleteRedirTalk(redirect_talk_ids[jj]);
} else {
// Page doesn't exists: skip it, check if all done
delrt_skip++;
if ( delrt_skip === redirect_talk_ids.length ) {
// No pages to delete
XFDcloser.taskFinished(nom_data.close_span_id, "15");
XFDcloser.taskWarning(nom_data.close_span_id, "15", "none found");
} else if ( delrt_count + delrt_skip === redirect_talk_ids.length ) {
// All done
XFDcloser.taskFinished(nom_data.close_span_id, "15");
}
}
}
}
}
};
apiCallback_getRedirects = function(result) {
var pid = result.query.pageids;
for (var ii=0; ii<pid.length; ii++)
if (result.query.pages[ pid[ii] ].redirects) {
var redirs = result.query.pages[ pid[ii] ].redirects;
for (var jj=0; jj<redirs.length; jj++) {
redirect_titles.push( redirs[jj].title );
if ( input_data.deletetalk && !XFDcloser.checkNamespace(redirs[jj].title, 2) ) {
redirect_talk_titles.push( XFDcloser.getTalkPage(redirs[jj].title) );
}
}
}
if (redirect_titles.length === 0) {
// Mark as closed - no redirects found
XFDcloser.taskFinished(nom_data.close_span_id, "10");
XFDcloser.taskWarning(nom_data.close_span_id, "10", "no redirects found");
if ( input_data.deletetalk ) {
XFDcloser.taskFinished(nom_data.close_span_id, "15");
XFDcloser.taskWarning(nom_data.close_span_id, "15", "no redirects found");
}
} else {
// Warn if there will be mass action, allow user to cancel
if ( redirect_titles.length >= 10 ) {
warn_redir = confirm("WARNING:\n Mass action to be peformed: delete " +
redirect_titles.length + " redirects.\nDo you want to proceed?");
if ( !warn_redir ) {
XFDcloser.taskError(nom_data.close_span_id, "11", "cancelled by user");
if ( input_data.deletetalk ) {
XFDcloser.taskError(nom_data.close_span_id, "15", "cancelled by user");
}
return;
}
}
// Delete redirects
for (var i=0; i<redirect_titles.length; i++) {
apiDeleteRedir(redirect_titles[i]);
}
if ( input_data.deletetalk ) {
if ( redirect_talk_titles.length === 0 ) {
// No pages to delete
XFDcloser.taskFinished(nom_data.close_span_id, "15");
XFDcloser.taskWarning(nom_data.close_span_id, "15", "none found");
} else {
// Delete redirects' talk pages - first get talkpage id's from api, so we don't
// attempt to delete non-existant talkpages (50 at a time - limit for api query)
for (var j=0; j<redirect_talk_titles.length; j+=50) {
new mw.Api().get( {
action: 'query',
titles: redirect_talk_titles.slice(j, j+49).join("|"),
indexpageids: 1
} ).done( apiCallback_getRedirectTalks )
.fail( apiFailedCallback_getRedirectTalks );
}
}
}
}
};
new mw.Api().get( {
action: 'query',
titles: nomtitles,
prop: 'redirects',
rdlimit: 500,
indexpageids: 1
} ).done( apiCallback_getRedirects )
.fail( apiFailedCallback_getRedirects );
};
// --- Task 11: unlinkBacklinks --- //
// AFD and FFD only
XFDcloser.doTask[11] = function(nom_data, input_data) {
// This section derived from the Twinkle unlink module:
// https://en.wikipedia.org/wiki/MediaWiki:Gadget-twinkleunlink.js
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "11");
var query = {};
// Arrays to hold concated results, will conatins objects
// such as {"pageid": 785732, "ns": 4, "title": "Wikipedia:About the Sandbox"}
var blresults = [];
var iuresults = [];
// var to hold the total number of backlinks & image usages to be processed, for checking if
// everything is done
var bl_and_iu_total = 0;
// vars to be incremented
var count_results = 0;
var count_unlinked = 0;
var count_skipped = 0;
// Reason to be used with edit summary
var edit_sum = "Removing link(s): [[" + nom_data.disc_link + "]] " +
"closed as " + input_data.result + xfdc.script_advert;
if ( xfdSetting.xfd_type === "ffd" ) {
edit_sum = "Removing link(s) / file usage(s): [[" + nom_data.disc_link + "]] " +
"closed as " + input_data.result + xfdc.script_advert;
}
// modal interface html
var unlink_modal_html = '<div id="unlinkXFD-modal" style="display:none;">'+
'<div id="unlinkXFD-interface">'+
'<h4 id="unlinkXFD-interface-header">XFDcloser Unlink</h4>'+
'<div id="unlinkXFD-interface-content">'+
'<p>All <span id="unlinkXFD-pagecount"></span> pages listed below may be edited '+
'(unless backlinks are only present due to transclusion of a template).</p>'+
'<p>To process only some of these pages, use Twinkle\'s unlink tool instead.</p>'+
'<p style="font-size:90%;">Use with caution, after reviewing the pages listed below. '+
'Note that the use of high speed, high volume editing software (such as this tool and '+
'Twinkle\'s unlink tool) is subject to <a href="https://en.wikipedia.org/wiki/WP:ASSISTED" '+
'target="_blank">Wikipedia:Bot policy#Assisted editing guidelines</a>.</p>'+
'<hr>'+
'</div>'+
'<div style="text-align:center;clear:both;" id="unlinkXFD-interface-buttons">'+
'<button id="unlinkXFD-interface-unlink" style="margin:1em;">Unlink</button>'+
'<button id="unlinkXFD-interface-cancel" style="margin:1em;">Cancel</button>'+
'</div>'+
'</div>'+
'</div>';
apiFailedCallback_editBlPages = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "11", "remove backlink(s)", code, result );
};
//6) Edit pages
editBlPages = function(page_title, replace_wikitext) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: page_title,
text: replace_wikitext,
summary: edit_sum,
minor: 1,
nocreate: 1
} ).done( function() {
count_unlinked++;
if (count_unlinked + count_skipped === bl_and_iu_total) {
XFDcloser.taskFinished(nom_data.close_span_id, "11");
if ( count_skipped > 0 ) {
XFDcloser.taskWarning(nom_data.close_span_id, "11", count_skipped +
" page(s) with no direct backlinks skipped, details logged to javascript console " +
"<span style='font-size:85%;'>(<a href='http://webmasters.stackexchange.com/questions/8525/how-to-open-the-javascript-console-in-different-browsers#answer-77337' " +
"target='_blank' class='external'>?</a>)</span>");
}
}
} ).fail( apiFailedCallback_editBlPages );
};
apiFailedCallback_getWikitext = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "11", "read contents of page(s); could not " +
"remove backlink(s)", code, result );
};
//4) For each backlink's wikitext, pass it through the unlink function; edit the page if needed
var changed = 0; //var to increment, so not too many edits are made at once
apiCallback_getWikitext = function(result) {
var page_ids = result.query.pageids;
for ( var pp = 0; pp<page_ids.length; pp++ ) {
old_wikitext = result.query.pages[ page_ids[pp] ].revisions[0]['*'];
//If this is a disambiguation page, change namespace to -7
if ( result.query.pages[ page_ids[pp] ].categories ) {
result.query.pages[ page_ids[pp] ].ns = -7;
}
new_wikitext = XFDcloser.unlink(old_wikitext, nom_data.pages, result.query.pages[ page_ids[pp] ].ns);
if ( old_wikitext !== new_wikitext ) {
changed++;
// Pause for a bit before editing
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) { //non-infinite loop that shoud still take awhile
if ( (new Date().getTime() - start) > 600 ) { //delay in milliseconds
break;
}
}
// edit summary depeneds on if it is a file or not
editBlPages(result.query.pages[ page_ids[pp] ].title, new_wikitext);
} else { // skip (and log to console)
count_skipped++;
console.log("[XFDcloser] Skipped unlinking \"" +
result.query.pages[ page_ids[pp] ].title + "\" (no backlinks found)");
if (count_unlinked + count_skipped === bl_and_iu_total) {
XFDcloser.taskFinished(nom_data.close_span_id, "11");
if ( count_skipped > 0 ) {
XFDcloser.taskWarning(nom_data.close_span_id, "11", count_skipped +
" page(s) with no direct backlinks skipped, details logged to javascript console " +
"<span style='font-size:85%;'>(<a href='http://webmasters.stackexchange.com/questions/8525/how-to-open-the-javascript-console-in-different-browsers#answer-77337' " +
"target='_blank' class='external'>?</a>)</span>");
}
}
}
}
};
//3) List affected pages, notify that Twinkle is an alternative
processBacklinks = function() {
// Make modal interface
$("body").prepend(unlink_modal_html);
//Change list items into links
//Apply styles
$("#unlinkXFD-modal").css({
"display": "none",
"position": "fixed",
"z-index": "1",
"left": "0",
"top": "0",
"width": "100%",
"height": "100%",
"overflow": "auto",
"background-color": "rgba(0,0,0,0.4)"
});
$("#unlinkXFD-interface").css({
"background-color": "#f0f0f0",
"margin": "15% auto",
"padding": "2px 20px",
"border": "1px solid #888",
"width": "80%",
"max-width": "60em",
"font-size": "90%",
"overflow": "auto"
});
$("#unlinkXFD-interface-content").css({
"border": "1px solid #ccc",
"overflow-y": "scroll",
"max-height": "20em",
"background": "#fdfdfd"
});
// Arrays to hold just the titles
var bltitles = [];
var iutitles = [];
//convert results (arrays of objects) to titles (arrays of strings), removing duplicates
if ( iuresults.length !== 0 ) {
for (var iui = 0; iui < iuresults.length; iui++) {
if ( $.inArray(iuresults[iui].title, iutitles) === -1 ) {
iutitles.push(iuresults[iui].title);
}
}
}
for (var bli = 0; bli < blresults.length; bli++) {
if ( $.inArray(blresults[bli].title, bltitles) === -1 && $.inArray(blresults[bli].title, iutitles) === -1 ) {
bltitles.push(blresults[bli].title);
}
}
// List file usage in modal (if any)
if ( iutitles.length > 1 ) {
$("#unlinkXFD-interface-content").append("<h5>File usage (and backlinks, if any):</h5>"+
"<ul><li>" + iutitles.join('</li><li>') + '</li></ul>');
} else if ( iutitles.length === 1 ) {
var append_iu = "<h5>File usage (and backlinks, if any):</h5>"+
"<ul><li>" + iutitles[0] + "</li></ul>";
$("#unlinkXFD-interface-content").append(append_iu);
}
// List backlinks in modal (if any)
if ( bltitles.length > 1 ) {
$("#unlinkXFD-interface-content").append("<h5>Backlinks:</h5>"+
"<ul><li>" + bltitles.join('</li><li>') + '</li></ul>');
} else if ( bltitles.length === 1 ) {
var append_bl = "<h5>Backlinks:</h5>"+
"<ul><li>" + bltitles[0] + "</li></ul>";
$("#unlinkXFD-interface-content").append(append_bl);
}
//Change plaintext titles into links
$("#unlinkXFD-interface-content li").each(function() {
var tt = $(this).text();
var ttlink = '<a href="https://en.wikipedia.org/wiki/' +
mw.util.wikiUrlencode(tt) + '" target="_blank">' +
tt + '</a>';
$(this).html(ttlink);
});
//Count pages
$("#unlinkXFD-pagecount").text(iutitles.length + bltitles.length);
// Now show modal
$("#unlinkXFD-modal").show();
// Cancel button clicked
$("#unlinkXFD-interface-cancel, #unlinkXFD-interface-close").click(function(){
unlinking_cancelled = true;
$("#unlinkXFD-modal").remove();
XFDcloser.taskFinished(nom_data.close_span_id, "11");
XFDcloser.taskWarning(nom_data.close_span_id, "11", "cancelled by user");
});
// Unlink button clicked
$("#unlinkXFD-interface-unlink").click(function(){
$("#unlinkXFD-modal").remove();
bl_and_iu_titles = iutitles.concat(bltitles);
bl_and_iu_total = bl_and_iu_titles.length;
// get wikitext of titles, check if in the dab category
for (var ii=0; ii<bl_and_iu_total; ii+=50) {
new mw.Api().get( {
action: "query",
titles: bl_and_iu_titles.slice(ii, ii+49).join("|"),
prop: "categories|revisions",
clcategories: "Category:All disambiguation pages",
rvprop: "content",
indexpageids: 1
} ).done( apiCallback_getWikitext )
.fail( apiFailedCallback_getWikitext );
}
});
};
apiFailedCallback_getBacklinks = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "11", "get backlinks", code, result );
};
//2) Callback to process api results
apiCallback_getBacklinks = function (result) {
if ( result.query.backlinks ) {
blresults = blresults.concat(result.query.backlinks);
}
if ( result.query.imageusage ) {
iuresults = iuresults.concat(result.query.imageusage);
}
if ( result.continue ) {
// More results to come, do another query
jQuery.extend(query, result.continue);
if ( !result.continue.blcontinue ) delete query.blcontinue;
if ( !result.continue.iucontinue ) delete query.iucontinue;
new mw.Api().get( query )
.done( apiCallback_getBacklinks )
.fail( apiFailedCallback_getBacklinks );
} else {
// All results for this page done
count_results++;
if ( count_results === nom_data.pages.length ) {
// All nominated pages done, check if there is anything to do
if ( blresults.length === 0 && iuresults.length === 0 ) {
//no backlinks or image usages
XFDcloser.taskFinished(nom_data.close_span_id, "11");
XFDcloser.taskWarning(nom_data.close_span_id, "11", "none found");
return;
} else {
processBacklinks();
}
} else {
// Start query for next nominated page
query.bltitle = nom_data.pages[count_results];
if ( query.iutitle ) query.iutitle = nom_data.pages[count_results];
delete query.continue;
delete query.blcontinue;
delete query.iucontinue;
new mw.Api().get( query )
.done( apiCallback_getBacklinks )
.fail( apiFailedCallback_getBacklinks );
}
}
};
//1) Get backlinks (in namespaces 0, 10, 100, 118)
if( xfdSetting.xfd_type === "ffd" ) { // File:
query = {
action: 'query',
list: [ 'backlinks', 'imageusage' ],
bltitle: nom_data.pages[0],
iutitle: nom_data.pages[0],
blfilterredir: 'nonredirects',
iufilterredir: 'nonredirects',
bllimit: xfdc.isSysop ? 5000 : 500, // Max for sysop / normal
iulimit: xfdc.isSysop ? 5000 : 500, // Max for sysop / normal
blnamespace: xfdc.unlink_ns,
iunamespace: xfdc.unlink_ns
};
} else {
query = {
action: 'query',
indexpageids: 1,
list: 'backlinks',
bltitle: nom_data.pages[0],
blfilterredir: 'nonredirects',
bllimit: xfdc.isSysop ? 5000 : 500, // Max for sysop / normal
blnamespace: xfdc.unlink_ns
};
}
new mw.Api().get( query )
.done( apiCallback_getBacklinks )
.fail( apiFailedCallback_getBacklinks );
};
// --- Task 12: redirect each nominated page to target --- //
XFDcloser.doTask[12] = function(nom_data, input_data, delete_first, task_number) {
// Default values if params are not defined
if ( delete_first == null ) {
delete_first = false;
}
if ( task_number == null ) {
task_number = "12";
}
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, task_number);
var count_r = 0; // var to increment after each edit
var rcatshell = "\n\n{{Rcat shell}}";
if ( input_data.rcats === false ) {
rcatshell = "";
} else if ( input_data.rcats !== "" ) {
rcatshell = "\n\n{{Rcat shell|\n" + input_data.rcats + "\n}}";
}
// Replacement wikitext to make redirect
if ( input_data.softredir ) {
redirect_wikitext = "{{Soft redirect|" + input_data.target + input_data.targetFrag + "}}" + rcatshell;
} else {
redirect_wikitext = "#REDIRECT " + input_data.targetLink + rcatshell;
}
// Edit summary
var edit_sum = "[[" + nom_data.disc_link + "]] closed as " + input_data.result + xfdc.script_advert;
var del_reason = "[[" + nom_data.disc_link + "]]" + xfdc.script_advert;
// Callback functions
apiFailedCallback_editMakeRedirect = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, task_number, "edit page(s) to make redirect(s)", code, result );
};
apiFailedCallback_deleteBeforeRedir = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, task_number, "delete page(s)", code, result );
};
//Function to make a redirect
apiEditMakeRedirect = function(page_title) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: page_title,
text: redirect_wikitext,
summary: edit_sum
} ).done( function() {
count_r++;
if (count_r === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, task_number);
}
} ).fail( apiFailedCallback_editMakeRedirect );
};
// Function to delete a redirect
apiDeleteBeforeRedir = function(pagetitle) {
new mw.Api().postWithToken( 'csrf', {
action: 'delete',
title: pagetitle,
reason: del_reason,
} ).done( function() {
//Page deleted, now create redirect in its place
apiEditMakeRedirect(pagetitle);
} ).fail( apiFailedCallback_deleteBeforeRedir );
};
// For each page, check that it isn't the target, then make it into a redirect
for (var i=0; i<nom_data.pages.length; i++) {
if (nom_data.pages[i] === input_data.target) {
//Skip (don't make a page redirect to itself) - just increment count and check if done
count_r++;
if (count_r === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, task_number);
}
} else if (delete_first) {
apiDeleteBeforeRedir(nom_data.pages[i]);
} else {
apiEditMakeRedirect(nom_data.pages[i]);
}
}
};
// --- Task 13: Delete each nominated page and then redirect --- //
XFDcloser.doTask[13] = function(nom_data, input_data) {
// Do by calling task 12 with extra parameters
XFDcloser.doTask[12](nom_data, input_data, true, "13");
};
// --- Task 14: Unlink circular links from redirect target --- //
XFDcloser.doTask[14] = function(nom_data, input_data) {
editsum = "Unlinking circular redirects – [[" + nom_data.disc_link + "]] closed as " +
input_data.result + xfdc.script_advert;
// Notify task is started
XFDcloser.taskStarted(nom_data.close_span_id, "14");
// Api failure callbacks
apiFailedCallback_editRedirectTarget = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "14", "edit redirect target", code, result );
};
apiFailedCallback_getRedirectTarget = function (code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "14", "delete page(s)", code, result );
};
// Function to edit redirect
apiEditRedirectTarget = function (new_wikitext) {
new mw.Api().postWithToken( 'csrf', {
action: 'edit',
title: input_data.target,
text: new_wikitext,
summary: editsum
} ).done( function() {
XFDcloser.taskFinished(nom_data.close_span_id, "14");
} ).fail( apiFailedCallback_editNomPage );
};
// Callback function for processing api result
apiCallback_getRedirectTarget = function (result) {
var p_id = result.query.pageids;
var p_wikitext = result.query.pages[ p_id ].revisions[ 0 ][ '*' ];
// Check if redirect target is one of the nominated pages (if it is, then index is not -1)
var j = nom_data.pages.indexOf(input_data.target);
// Unlink nomated pages
if ( j !== -1 ) {
// Don't want to unlink self-links, which may be to a section on the page
var unlink_pages = nom_data.pages.slice(); //first duplicate array...
unlink_pages.splice(j); //...then remove target from duplicted array
p_wikitext = XFDcloser.unlink(p_wikitext, unlink_pages);
} else {
p_wikitext = XFDcloser.unlink(p_wikitext, nom_data.pages);
}
// Check if any changes need to be made; if redirect target is a nominated page, remove
// nomination template and adjust edit summary
if ( p_wikitext === result.query.pages[ p_id ].revisions[ 0 ][ '*' ] ) {
if ( j !== -1 ) {
// No links to unlink, and the redirect target is one of the nominated pages
p_wikitext = p_wikitext.replace(xfdSetting.regex.nomTemplate, "");
editsum = xfdSetting.xfd_type.toUpperCase() + " closed as " +
input_data.result + xfdc.script_advert;
XFDcloser.taskWarning(nom_data.close_span_id, "14", "none found");
} else {
// No links to unlink, and no changes to be made
XFDcloser.taskFinished(nom_data.close_span_id, "14");
XFDcloser.taskWarning(nom_data.close_span_id, "14", "none found");
return;
}
} else if ( j !== -1 ) {
// There are links to unlink, and the redirect target is one of the nominated pages
p_wikitext = p_wikitext.replace(xfdSetting.regex.nomTemplate, "");
editsum = xfdSetting.xfd_type.toUpperCase() + " closed as " +
input_data.result + "; unlinking circular redirects" + xfdc.script_advert;
}
// Now make the edit
apiEditRedirectTarget(p_wikitext);
};
// Get redirect target wikitext
new mw.Api().get( {
action: 'query',
titles: input_data.target,
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getRedirectTarget )
.fail( apiFailedCallback_getRedirectTarget );
};
// --- Task 15: Delete redirect talk pages --- //
// (done as part of task 10)
XFDcloser.doTask[15] = function() {
return;
};
// Function to commence post-close tasks (which should not be started until xfd discussion is actually closed)
XFDcloser.doPostCloseTasks = function(nom_data, input_data, tasks) {
for (var ii = 1; ii < tasks.length; ii++) {
XFDcloser.doTask[ tasks[ii] ](nom_data, input_data);
}
};
//Process closing info
XFDcloser.processClose = function(nom_data, input_data) {
xfdc.started++;
$XFDClosing = $("#" + nom_data.close_span_id);
var task_12_text = "Making page(s) into redirect(s)...";
if ( xfdSetting.xfd_type === "rfd" ) {
task_12_text = "Retargeting redirect(s)...";
}
tasks_html = "<div style='width:80%;font-size:92%;color:#777;float:left;clear:right;padding:0px 10px;'>"+
"<p class='XFDcloser-task-0' style='display:none;margin:0;'>"+
"Closing discussion....</p>"+
"<p class='XFDcloser-task-1' style='display:none;margin:0;'>"+
"Updating talk page(s)...</p>"+
"<p class='XFDcloser-task-2' style='display:none;margin:0;'>"+
"Updating page(s)...</p>"+
"<p class='XFDcloser-task-3' style='display:none;margin:0;'>"+
"Updating page(s)...</p>"+
"<p class='XFDcloser-task-4' style='display:none;margin:0;'>"+
"Deleting page(s)...</p>"+
"<p class='XFDcloser-task-5' style='display:none;margin:0;'>"+
"Tagging page(s) for speedy deletion...</p>"+
"<p class='XFDcloser-task-6' style='display:none;margin:0;'>"+
"Updating template(s)...</p>"+
"<p class='XFDcloser-task-7' style='display:none;margin:0;'>"+
"Listing at holding cell...</p>"+
"<p class='XFDcloser-task-8' style='display:none;margin:0;'>"+
"Deleting talk page(s)...</p>"+
"<p class='XFDcloser-task-9' style='display:none;margin:0;'>"+
"Tagging talk page(s) for speedy deletion...</p>"+
"<p class='XFDcloser-task-10' style='display:none;margin:0;'>"+
"Deleting redirects...</p>"+
"<p class='XFDcloser-task-15' style='display:none;margin:0;'>"+
"Deleting redirects' talk pages...</p>"+
"<p class='XFDcloser-task-11' style='display:none;margin:0;'>"+
"Unlinking backlinks...</p>"+
"<p class='XFDcloser-task-12' style='display:none;margin:0;'>"+
task_12_text + "</p>"+
"<p class='XFDcloser-task-13' style='display:none;margin:0;'>"+
"Deleting page(s) and replacing with redirect(s)...</p>"+
"<p class='XFDcloser-task-14' style='display:none;margin:0;'>"+
"Unlinking circular links on redirect target...</p>"+
"</div>";
$XFDClosing.html(tasks_html).prev().css("float", "left");
tasksToDo = [];
xfdc.tasks_completed[nom_data.close_span_id] = 0; //number of tasks completed
tasksToDo.push(0); //closeSection
if ( input_data.after === "doKeepActions" ){
tasksToDo.push(1); //addOldXfd
tasksToDo.push(2); //removeNomTemplate
} else if ( input_data.after === "doRedirectActions" ) {
tasksToDo.push(1); //addOldXfd
if ( input_data.delAndRedir ) {
tasksToDo.push(13); //deleteThenRedirect
} else {
tasksToDo.push(12); //redirect
}
if ( !input_data.softredir ) {
tasksToDo.push(14); //removeCircularLinks
}
} else if ( input_data.after === "doMergeActions" && xfdSetting.xfd_type !== "tfd" ) {
tasksToDo.push(1); //addOldXfd
tasksToDo.push(3); //addMergeTemplates
} else if ( input_data.after === "doDeletion" ) {
tasksToDo.push(4); //peformDelete
if ( input_data.deletetalk ) {
tasksToDo.push(8); //deleteTalk
}
} else if ( input_data.after === "tagSpeedy" ) {
tasksToDo.push(5); //tagWithSpeedy
if ( input_data.deletetalk ) {
tasksToDo.push(9); //tagTalkWithSpeedy
}
} else if ( (input_data.after === "holdingCell") ||
(input_data.after === "doMergeActions" && xfdSetting.xfd_type === "tfd") ) {
tasksToDo.push(6); //addBeingDeleted
tasksToDo.push(7); //addToHoldingCell
if ( input_data.deletetalk ) {
tasksToDo.push(9); //tagTalkWithSpeedy
}
}
if ( input_data.deleteredir && (input_data.after !== "noAction") ) {
tasksToDo.push(10); //deleteRedirects
if ( input_data.deletetalk ) {
tasksToDo.push(15); //deleteRedirectsTalks
}
}
if ( input_data.unlinkbackl && (input_data.after !== "noAction") ) {
tasksToDo.push(11); //unlinkBacklinks
}
xfdc.tasks_to_do[nom_data.close_span_id] = tasksToDo.length; //number of tasks to be done
xfdc.task_errors[nom_data.close_span_id] = new Array(tasksToDo.length);
// Notify which tasks are to be done
for (var i = 0; i < tasksToDo.length; i++){
XFDcloser.updateTask(nom_data.close_span_id, tasksToDo[i].toString());
}
//Close section (and then start doing post-close tasks)
XFDcloser.doTask[0](nom_data, input_data, tasksToDo);
};
/* == Relisting-related functions == */
/* ********************************* */
//Steps
//1: Grab wikitext from old discussion (and if AFD, also get log page it is transcluded onto)
//2: Append relisting note to wikitext from old discussion
//3: [non-AFD only] Make closed-as-relist-wikitext, removing discussion but keeping page links
//4: Replace old log page entry with closed-as-relist-wikitext [non-AFD] / remove (replace with "")
// transclusion from old log page [AFD]
//5: Add discussion/transclusion to today's log page
//6: Update nom templates on nominated pages
//note: CfD doesn't reslist
XFDcloser.processRelist = function(nom_data, relist_comment) {
// Parts of this section derived from https://en.wikipedia.org/wiki/User:Mr.Z-man/closeAFD2.js
xfdc.started++;
$XFDClosing = $("#" + nom_data.close_span_id);
$XFDClosing.prev().css("float", "left");
var afdLogEditIndex = 0;
if ( xfdSetting.xfd_type === "afd" ) {
// add a Deferred() for when this relist has finished editing the log page, keep track of it
// using its array index
afdLogEditIndex = xfdc.afdLogEdit.push($.Deferred()) - 1;
$("<div>")
.attr('id', 'XFDcloser-waiting-'+afdLogEditIndex)
.css({
'width':'80%',
'font-size':'92%',
'color':'#777',
'float':'left',
'clear':'right',
'padding':'0px 10px'
})
.text("Waiting... (to avoid edit conflicts, previous relistings need to be completed)")
.appendTo($XFDClosing);
}
var startRelist = function(nom_data, relist_comment, afdLogEditIndex) {
$XFDClosing = $("#" + nom_data.close_span_id);
$("#XFDcloser-waiting-"+afdLogEditIndex).hide();
// Today's new, new log page path
var today = new Date();
var curdate = today.getUTCFullYear().toString() + " " + xfdc.monthnames[today.getUTCMonth()] +
" " + today.getUTCDate().toString();
var todays_logpage = xfdSetting.path + curdate;
var task1_text = "Removing from old log page...";
if ( xfdSetting.xfd_type == "afd" ) {
task1_text = "Removing from <span id='" + nom_data.close_span_id + "_oldlogpage'>old log page</span>...";
} else if ( xfdSetting.xfd_type == "ffd" || xfdSetting.xfd_type == "rfd" || xfdSetting.xfd_type == "tfd" ) {
task1_text = "Removing from " + XFDcloser.makeLink(nom_data.nom_page, "old log page") + "...";
}
// Tasks to be done
tasks_html = "<div style='width:80%;font-size:92%;color:#777;float:left;clear:right;padding:0px 10px;'>"+
"<p class='XFDcloser-task-0' style='display:none;margin:0;'>"+
"Editing discussion....</p>"+
"<p class='XFDcloser-task-1' style='display:none;margin:0;'>"+
task1_text + "</p>"+
"<p class='XFDcloser-task-2' style='display:none;margin:0;'>"+
"Adding to " + XFDcloser.makeLink(todays_logpage, "today's log page") + "...</p>"+
"<p class='XFDcloser-task-3' style='display:none;margin:0;'>"+
"Updating link in nominations template(s)...</p>"+
"</div>";
$XFDClosing.html(tasks_html);
// Tasks to be done depend on xfd type
if ( xfdSetting.xfd_type === "afd" ) {
tasksToDo = [0, 1, 2];
} else if ( xfdSetting.xfd_type === "mfd" ) {
tasksToDo = [0];
} else if ( xfdSetting.xfd_type === "rfd" ) {
tasksToDo = [1, 2];
} else {
tasksToDo = [1, 2, 3];
}
xfdc.tasks_to_do[nom_data.close_span_id] = tasksToDo.length;
xfdc.task_errors[nom_data.close_span_id] = new Array(tasksToDo.length);
xfdc.tasks_completed[nom_data.close_span_id] = 0; //number of tasks completed
for (var i = 0; i < tasksToDo.length; i++){
XFDcloser.updateTask(nom_data.close_span_id, tasksToDo[i].toString());
}
// Edit summaries
var editsum_closeAsRelist = "/* " + nom_data.section_header + " */ Closed as relisted on " +
"[[" + todays_logpage + "#" + nom_data.section_header + "|" + curdate + "]]" +
xfdc.script_advert;
if ( xfdSetting.xfd_type === "rfd" ) {
editsum_closeAsRelist = "/* " + nom_data.section_header + " */ Relisted on " +
"[[" + todays_logpage + "#" + nom_data.section_header + "|" + curdate + "]]" +
xfdc.script_advert;
}
var editsum_relistingOn = "Relisting discussion on " + curdate + xfdc.script_advert;
var editsum_newLogpageSection = "Relisting \"" + nom_data.section_header +
"\"" +xfdc.script_advert;
var editsum_logpageTransclusion = "Relisting [[" + nom_data.nom_page +
"]]" + xfdc.script_advert;
var editsum_discussion = "Relisting discussion" + xfdc.script_advert;
var editsum_updateNomTemplate = "Updating " + xfdSetting.xfd_type.toUpperCase() +
" template: discussion was relisted" + xfdc.script_advert;
// Vars to be available to multiple subfunctions
var new_disc_wikitext = "";
var closed_disc_wikitext = "";
var oldlogtitle = "";
var nomTemplates_updated = 0; //var to increment
// Callbacks for functions to edit pages via api
apiFailedCallback_editRelistDisc = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "0", "edit " +
xfdSetting.xfd_type.toUpperCase() + " discussion", code, result );
};
apiCallback_editRelistDisc = function() {
XFDcloser.taskFinished(nom_data.close_span_id, "0");
};
apiFailedCallback_editOldLogpage = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "1", "edit old " +
xfdSetting.xfd_type.toUpperCase() + " log page", code, result );
if ( afdLogEditIndex ) {
xfdc.afdLogEdit[afdLogEditIndex].resolve();
}
};
apiCallback_editOldLogpage = function() {
XFDcloser.taskFinished(nom_data.close_span_id, "1");
if ( afdLogEditIndex ) {
xfdc.afdLogEdit[afdLogEditIndex].resolve();
}
};
apiFailedCallback_editNewLogpage = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "2", "edit old " +
xfdSetting.xfd_type.toUpperCase() + " log page", code, result );
};
apiCallback_editNewLogpage = function() {
XFDcloser.taskFinished(nom_data.close_span_id, "2");
};
apiFailedCallback_editNomTemplates = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "3", "update link in nomination " +
"template(s)", code, result );
};
apiCallback_editNomTemplates = function() {
nomTemplates_updated++;
if (nomTemplates_updated === nom_data.pages.length) {
XFDcloser.taskFinished(nom_data.close_span_id, "3");
}
};
// Function to edit pages via api
apiEditPage = function (api_params, done_callback, fail_callback) {
new mw.Api().postWithToken( 'csrf', api_params)
.done( done_callback )
.fail( fail_callback );
};
// Function to update nomination templates can be updated
updateNomTemplates = function() {
// Calbacks for getting pages' wikitext
apiFailedCallback_getPagesWikitext = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "3", "read content of pages", code, result);
};
apiCallback_getPagesWikitext = function(result) {
//Get old wikitext, or make error if page doesn't exist, or if page is in wrong namespace
var oldwikitext = "";
var page_ids = result.query.pageids;
for (var i = 0; i < page_ids.length; i++) {
var p_title = result.query.pages[ page_ids[i] ].title;
// Check that subject page exists
j = nom_data.pages.indexOf(p_title);
if ( j === -1 ) {
XFDcloser.taskError(nom_data.close_span_id, "3", "API: query result included " +
"unexpected page title \"" + XFDcloser.makeLink(p_title) + "\"; " +
"this page will not be edited");
} else if ( parseInt(page_ids[i]) < 0 ) { //more recent info than nom_data.pageExists[j]
XFDcloser.taskError(nom_data.close_span_id, "3", "The page \"" +
XFDcloser.makeLink(p_title) + "\" does not exist, and will not be edited");
} else {
oldwikitext = result.query.pages[ page_ids[i] ].revisions[ 0 ][ '*' ];
replace_str = xfdSetting.wikitext.relistReplace.replace("__TODAY__", curdate);
updated_wikitext = oldwikitext.replace(xfdSetting.regex.relistPattern, replace_str);
apiEditPage({
action: 'edit',
title: p_title,
text: updated_wikitext,
summary: editsum_updateNomTemplate
}, apiCallback_editNomTemplates, apiFailedCallback_editNomTemplates);
}
}
};
if ( nom_data.pages[0]===-1 ) {
XFDcloser.taskError(nom_data.close_span_id, "3", "nominated pages were not detected, " +
"and were not edited");
return;
}
//get each nominated page's wikitext through api
new mw.Api().get( {
action: 'query',
titles: nom_data.pages.join("|"),
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ) .done( apiCallback_getPagesWikitext )
.fail( apiFailedCallback_getPagesWikitext );
};
// Callbacks for getting new & old logpage (AFDs)
apiFailedCallback_getLogpages = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "0", "read contents of " +
"log page(s)", code, result );
if ( afdLogEditIndex ) {
xfdc.afdLogEdit[afdLogEditIndex].resolve();
}
};
apiCallback_getLogpages = function(result) {
//get wikitext
var newlogtext = "";
var oldlogtext = "";
log_ids = result.query.pageids;
if ( result.query.pages[ log_ids[0] ].title === todays_logpage ) {
//log_ids[0] is the new log page
newlogtext = result.query.pages[ log_ids[0] ].revisions[ 0 ][ '*' ];
oldlogtext = result.query.pages[ log_ids[1] ].revisions[ 0 ][ '*' ];
} else {
//log_ids[0] is the old log page
newlogtext = result.query.pages[ log_ids[1] ].revisions[ 0 ][ '*' ];
oldlogtext = result.query.pages[ log_ids[0] ].revisions[ 0 ][ '*' ];
}
//test for transclusion of nompage
var t = mw.RegExp.escape(nom_data.nom_page);
var patt = new RegExp("<!-- ?\\{\\{" + t + "\\}\\} ?-->", 'i' );
var res = patt.exec(oldlogtext);
if (res) {
XFDcloser.taskError(nom_data.close_span_id, "0", "Discussion appears to be relisted " +
"already [relist aborted]");
xfdc.afdLogEdit[afdLogEditIndex].resolve();
return;
}
// Updated new log wikitext:
var newlogreg = new RegExp("<!-- Add new entries to the TOP of the following list -->", "i");
newlogtext = newlogtext.replace(newlogreg, "<!-- Add new entries to the TOP of the following list -->\n"+
"{" + "{" + nom_data.nom_page + "}}<!--Relisted-->");
// Updated old log wikitext:
var oldlogreg = new RegExp("(\\{\\{" + t + "\\}\\})", 'i' );
// Check if tranbsclusion found by regex
var transclusion_found = oldlogreg.test(oldlogtext);
oldlogtext = oldlogtext.replace(oldlogreg, "<!-- $1 -->");
//Now we can make the edits...
//Edit discussion
apiEditPage({
action: 'edit',
title: nom_data.nom_page,
text: new_disc_wikitext,
summary: editsum_discussion
}, apiCallback_editRelistDisc, apiFailedCallback_editRelistDisc);
//Edit old logpage, or show error if transclusion was not found
if ( transclusion_found ) {
apiEditPage({
action: 'edit',
title: oldlogtitle,
text: oldlogtext,
summary: editsum_logpageTransclusion
}, apiCallback_editOldLogpage, apiFailedCallback_editOldLogpage);
} else {
XFDcloser.taskError(nom_data.close_span_id, "1", "Transclusion \"{{" + t + "}}\" "+
"was not found on old log page, and could not be commented out");
xfdc.afdLogEdit[afdLogEditIndex].resolve();
}
//Edit today's logpage
apiEditPage({
action: 'edit',
title: todays_logpage,
text: newlogtext,
summary: editsum_logpageTransclusion
}, apiCallback_editNewLogpage, apiFailedCallback_editNewLogpage);
};
// Callbacks for getting today's logpage (TFDs & RFDs)
apiFailedCallback_getTodaysLogpage = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "0", "read contents of " +
"today's log page \"" + XFDcloser.makeLink(todays_logpage) + "\"", code, result );
};
apiCallback_getTodaysLogpage = function(result) {
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
params_editNewLog = {
action: 'edit',
title: todays_logpage,
section: 2,
prependtext: new_disc_wikitext,
summary: editsum_newLogpageSection
};
} else {
// there are no level 4 headings on page - can append to section #1
params_editNewLog = {
action: 'edit',
title: todays_logpage,
section: 1,
appendtext: "\n" + new_disc_wikitext,
summary: editsum_newLogpageSection
};
}
//Now we can make the edits...
//Edit old logpage
apiEditPage({
action: 'edit',
title: nom_data.nom_page,
section: nom_data.editsection,
text: closed_disc_wikitext,
summary: editsum_closeAsRelist
}, apiCallback_editOldLogpage, apiFailedCallback_editOldLogpage);
//Edit today's logpage
apiEditPage(params_editNewLog, apiCallback_editNewLogpage, apiFailedCallback_editNewLogpage);
if ( xfdSetting.xfd_type !== "rfd" ) {
//Update nom templates on nominated pages
updateNomTemplates();
}
};
// Callbacks for getting relisting info
apiFailedCallback_getRelistingInfo = function(code, result) {
XFDcloser.Api_failed(nom_data.close_span_id, "0", "read contents of " +
xfdSetting.xfd_type.toUpperCase() + " discussion page", code, result );
if ( afdLogEditIndex ) {
xfdc.afdLogEdit[afdLogEditIndex].resolve();
}
};
apiCallback_getRelistingInfo = function (result) {
//grab wikitext of section
var p_id = result.query.pageids;
var disc_wikitext = result.query.pages[ p_id ].revisions[ 0 ][ '*' ];
var sec_heading = disc_wikitext.slice(0, disc_wikitext.indexOf("\n"));
//Check for number of relists, wikitext for relist template
var relist_number = 1;
relists = disc_wikitext.match(/\[\[Wikipedia:Deletion process#Relisting discussions\|Relisted\]\]/g);
if ( relists ) {
relist_number = relists.length + 1;
}
if ( !relist_comment ) {
relist_comment = "";
}
var relist_template = "\n{" + "{subst:Relist|1=" + relist_comment + "|2=" + relist_number + "}}\n";
//Make wikitext for the new (relisted) discussion
new_disc_wikitext = disc_wikitext.trim() + relist_template;
if ( xfdSetting.xfd_type === "afd" ) {
new_disc_wikitext = new_disc_wikitext.replace(/\[\[Wikipedia:Articles for deletion\/Log\/\d{4} \w+ \d{1,2}#/, "[["+todays_logpage+"#");
} else if ( xfdSetting.xfd_type === "ffd" || xfdSetting.xfd_type === "tfd" ) {
//Make wikitext for the closed (as relist) discussion
var xfd_close_top = xfdSetting.wikitext.closeTop
.replace(/__RESULT__/, "relisted")
.replace(/__TO_TARGET__/, " on [[" + todays_logpage + "#" +
nom_data.section_header + "|" + curdate + "]]")
.replace(/__RPUNCT__/, ".")
.replace(/__RATIONALE__/, "")
.replace(/__SIG__/, xfdc.sig);
var pages_list = "";
if ( nom_data.pages[0] !== -1 ) {
for (var i=0; i<nom_data.pages.length; i++) {
relative_title = nom_data.pages[i].replace(/.*?:/, ""); // remove namespace
pages_list += xfdSetting.wikitext.pagelinks.replace("__PAGE__", relative_title);
}
}
closed_disc_wikitext = sec_heading + "\n" + xfd_close_top + "\n" + pages_list +
xfdSetting.wikitext.closeBottom;
} else if ( xfdSetting.xfd_type === "mfd" ) {
//Find first linebeak after last pagelinks templats
var split_index = new_disc_wikitext.indexOf("\n", new_disc_wikitext.lastIndexOf(":{{pagelinks"));
var top_wikitext = new_disc_wikitext.slice(0, split_index);
var bottom_wikitext = new_disc_wikitext.slice(split_index+1);
//Make wikitext for the now relisted discussion
closed_disc_wikitext = top_wikitext.trim() + "\n{{subst:mfdr}}\n" + bottom_wikitext.trim();
} else if ( xfdSetting.xfd_type === "rfd" ) {
var top_wikitext_rfd = "====" + nom_data.section_header + "====";
if ( disc_wikitext.indexOf("*<span id=") !== disc_wikitext.lastIndexOf("*<span id=") ) {
//Multiple redirects were nominted, so keep nominated redirects' anchors
//Find first linebeak after last span with id
var split_index_1 = disc_wikitext.indexOf("\n", disc_wikitext.indexOf("*<span id=")-2);
var split_index_2 = disc_wikitext.indexOf("\n", disc_wikitext.lastIndexOf("*<span id="));
var rfd_anchors = disc_wikitext.slice(split_index_1, split_index_2)
.replace(/\*<span/g, "<span")
.replace(/^(?!<span).*$\n?/gm, "")
.replace(/>.*$\s*/gm, "></span>")
.trim();
top_wikitext_rfd += "\n<noinclude>" + rfd_anchors + "</noinclude>";
}
//Make wikitext for the closed (as relist) discussion
closed_disc_wikitext = top_wikitext_rfd + "\n{{subst:rfd relisted|page=" + curdate +
"|" + nom_data.section_header + "}}";
}
//Check that discussion is not already closed
if (disc_wikitext.indexOf('xfd-closed') !== -1) {
XFDcloser.taskError(nom_data.close_span_id, "1", "Discussion has been closed: " +
"relist aborted");
if ( afdLogEditIndex ) {
xfdc.afdLogEdit[afdLogEditIndex].resolve();
}
return;
}
//For AFDs, check that it's still transcluded to old log page...
if ( xfdSetting.xfd_type === "afd" ) {
//First get old logpage title
for (var ii=0; ii<result.query.embeddedin.length; ii++) {
if ( result.query.embeddedin[ii].title.indexOf(xfdSetting.path) !== -1) {
oldlogtitle = result.query.embeddedin[ii].title;
}
}
if ( oldlogtitle === "" ) {
//not transcluded anywhere, can skip removal from old log page
XFDcloser.taskError(nom_data.close_span_id, 0, "Old log page not found: " +
"relist aborted");
xfdc.afdLogEdit[afdLogEditIndex].resolve();
} else {
//set link in task message
var oldlogpagelink = XFDcloser.makeLink(oldlogtitle, "old log page");
$("#" + nom_data.close_span_id + "_oldlogpage").html(oldlogpagelink);
//get old logpage wikitext, process via callback function
new mw.Api().get( {
action: 'query',
titles: oldlogtitle + "|" + todays_logpage,
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ) .done( apiCallback_getLogpages )
.fail( apiFailedCallback_getLogpages );
}
} else if ( xfdSetting.xfd_type === "tfd" || xfdSetting.xfd_type === "rfd" ) {
//New discussions on top of log page, so need to check out current log page wikitext
new mw.Api().get( {
action: 'query',
titles: todays_logpage,
prop: 'revisions',
rvprop: 'content',
indexpageids: 1,
rawcontinue: ''
} ) .done( apiCallback_getTodaysLogpage )
.fail( apiFailedCallback_getTodaysLogpage );
} else if ( xfdSetting.xfd_type === "mfd" ) {
//Now we can make the edit nomination subpage (MFDs)
apiEditPage({
action: 'edit',
title: nom_data.nom_page,
section: nom_data.editsection,
text: closed_disc_wikitext,
summary: editsum_relistingOn
}, apiCallback_editRelistDisc, apiFailedCallback_editRelistDisc);
//Rest of relist process done by bot, per WP:MFDAI
} else {
//Now we can make the edits... (FFDs)
//Edit old logpage
apiEditPage({
action: 'edit',
title: nom_data.nom_page,
section: nom_data.editsection,
text: closed_disc_wikitext,
summary: editsum_closeAsRelist
}, apiCallback_editOldLogpage, apiFailedCallback_editOldLogpage);
//Edit today's logpage
apiEditPage({
action: 'edit',
title: todays_logpage,
appendtext: "\n" + new_disc_wikitext,
summary: editsum_newLogpageSection
}, apiCallback_editNewLogpage, apiFailedCallback_editNewLogpage);
//Update nom templates on nominated pages (FFDs)
updateNomTemplates();
}
};
//Step 1: get relisting info (discussion wikitext, and if AFD, log page it is transcluded onto)
var get_disc_params = {
action: 'query',
titles: nom_data.nom_page,
prop: 'revisions',
indexpageids: 1,
rawcontinue: 1,
rvprop: 'content',
rvsection: nom_data.editsection
};
if (xfdSetting.xfd_type === "afd") {
jQuery.extend(get_disc_params, {
list: 'embeddedin',
eititle: nom_data.nom_page,
einamespace: xfdc.eins,
eifilterredir: 'nonredirects',
eilimit: 500
});
// Need to fetch whole page, in order to check if afd is already closed
delete get_disc_params.rvsection;
}
new mw.Api().get( get_disc_params )
.done( apiCallback_getRelistingInfo )
.fail( apiFailedCallback_getRelistingInfo );
};
if ( afdLogEditIndex ) {
$.when(xfdc.afdLogEdit[afdLogEditIndex-1]).then(function(){
startRelist(nom_data, relist_comment, afdLogEditIndex);
});
} else {
startRelist(nom_data, relist_comment);
}
};
//End of full file closure wrappers
});
});
/* </nowiki> */