User:SD0001/RFUD-helper.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | This user script seems to have a documentation page at User:SD0001/RFUD-helper. |
/**
*
* Script to easily respond to requests made at [[Wp:Requests for undeletion]]
* (WP:RFUD). When accepting a request, the script would do the following:
* - Post a response below the request
* - Undelete the page
* - Remove any deletion tags from the page
* - Undelete the talk page if it existed
* - If is a WT:AFC subpage, move it to draft namespace
* - Offer to userfy the page instead of restoring to source
*
*/
// TODO: figure out how to make the dialog close after actions
// <nowiki>
$.when(
mw.loader.using([ 'mediawiki.util', 'mediawiki.api', 'mediawiki.Title', 'jquery.ui.dialog', 'jquery.tipsy' ]),
mw.loader.getScript( 'https://en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-morebits.js&action=raw&ctype=text/javascript' ),
importStylesheet( 'MediaWiki:Gadget-morebits.css' ),
$.ready
).then(function() {
if (mw.config.get('wgPageName') !== 'Wikipedia:Requests_for_undeletion') {
return;
}
// Until the patch to morebits is accepted, see #646
Morebits.status.actionCompleted = function(text) {
var node = document.createElement( 'div' );
node.appendChild( document.createElement('span') ).appendChild( document.createTextNode( text ) );
node.className = 'tw_status_info';
if (Morebits.status.root) {
Morebits.status.root.appendChild( node );
}
};
var rfud = {};
window.rfud = rfud;
rfud.advert = ' ([[User:SD0001/RFUD-helper.js|RFUD-helper]])';
Morebits.wiki.api.setApiUserAgent('[[w:User:SD0001/RFUD-helper.js|RFUD-helper]]');
var pageName;
var params = {};
rfud.params = params;
rfud.callback = function(e) {
e.preventDefault();
pageName = e.target.parentElement.childNodes[1].title.slice(17).replace(/_/g,' ');
rfud.sectionName = pageName;
var template_element = e.target.parentElement.parentElement.parentElement;
var header_element = template_element.previousElementSibling;
while (header_element.tagName !== 'H2') {
header_element = header_element.previousElementSibling;
}
rfud.sectionName = header_element.firstChild.textContent;
if (rfud.sectionName === '') {
rfud.sectionName = header_element.firstChild.nextElementSibling.textContent;
}
var buttonResponse = e.target.classList[1].slice('rfud-'.length);
var Window = new Morebits.simpleWindow( 700, 500 );
Window.setTitle( "Respond to undeletion request of " + pageName );
Window.setScriptName( "RFUD helper" );
Window.addFooterLink( "Administrator instructions", "Wikipedia:Requests for undeletion/Administrator instructions" );
// Window.addFooterLink( "Script documentation", "WP:RFUDHELPER" );
var form = new Morebits.quickForm( rfud.evaluate );
if (pageName === 'Page name goes here') {
form.append({
type: 'div',
label: Morebits.htmlNode('div', 'Caution: Accepting this will undelete "Page name goes here", please fix the template usage before proceeding.', 'red')
});
}
else if (pageName !== rfud.sectionName) {
form.append({
type: 'div',
label: Morebits.htmlNode('div', 'Note: page name used in template is different from the section name', 'red')
});
}
var field = form.append({
type: 'field',
label: 'Response'
});
field.append({
type: 'radio',
name: 'response',
list: [
{
label: 'Accept',
value: 'accept',
checked: buttonResponse === 'accept'
},
{
label: 'Decline',
value: 'decline',
checked: buttonResponse === 'decline'
}
],
event: rfud.toggleResponse
});
form.append( {
type: 'field',
label: 'Work area',
name: 'work_area'
} );
var previewlink = document.createElement( 'a' );
previewlink.addEventListener('click', function() {
rfud.preview(result); // `result` is defined below
});
previewlink.style.cursor = "pointer";
previewlink.textContent = 'Preview';
form.append( { type: 'div', id: 'rfudpreview', label: [ previewlink ] } );
form.append( { type: 'div', id: 'rfud-previewbox', style: 'display: none' } );
form.append( { type:'submit' } );
var result = form.render();
Window.setContent(result);
Window.display();
result.previewer = new Morebits.wiki.preview(document.getElementById('rfud-previewbox'));
// Init the controls
var evt = document.createEvent( "Event" );
evt.initEvent( 'change', true, true );
result.response[ buttonResponse === 'accept' ? 0 : 1 ].dispatchEvent( evt );
};
rfud.toggleResponse = function(e) {
var form = e.target.form;
var work_area;
if (e.target.value === 'accept') {
work_area = new Morebits.quickForm.element({
type: 'field',
label: 'Accept request',
name: 'work_area'
});
var permanent_section_link = 'Special:Permalink/' + mw.config.get('wgRevisionId') + '#' + rfud.sectionName;
work_area.append({
type: 'input',
label: 'Undeletion summary',
name: 'logsummary',
tooltip: 'Summary for the deletion log',
size: '66px',
value: 'Undelete per [[' + permanent_section_link + '|request]] at [[WP:RFUD]]'
});
work_area.append({
type: 'checkbox',
list: [ {
label: 'Userfy this page',
name: 'userfy',
value: 'userfy',
checked: false,
subgroup: [ {
type: 'input',
label: 'Userfy to: ',
name: 'page',
size: '60px',
tooltip: 'User page to which the page is to be moved',
value: 'User:USERNAME/' + pageName.replace(/^Draft:/, '')
.replace(/^Wikipedia talk:Articles for creation\//, '')
}, {
type: 'checkbox',
list: [ {
label: 'Suppress redirect',
name: 'sredr',
checked: true
} ]
} ],
event: function(e) {
if (e.target.checked) {
var userfypagefield = form['userfy.page'];
if (userfypagefield.value.includes('USERNAME')) {
userfypagefield.setSelectionRange('User:'.length, 'User:USERNAME'.length);
userfypagefield.focus();
}
form.template.value = '{{UND|userfy}}';
if (form.movetodraft) {
form.movetodraft.checked = false;
form.movetodraft.disabled = true;
} else if (form.undeletetalk) {
form.undeletetalk.checked = false;
form.undeletetalk.disabled = true;
}
} else {
form.template.value = '{{UND|done}}';
if (form.movetodraft) {
form.movetodraft.disabled = false;
} else if (form.undeletetalk) {
form.undeletetalk.disabled = false;
}
}
}
} ]
});
if (! mw.Title.newFromText(pageName).isTalkPage()) {
work_area.append({
type: 'checkbox',
list: [ {
label: 'Undelete talk page if it existed',
name: 'undeletetalk',
value: 'undeletetalk',
checked: true
} ]
});
}
if (pageName.startsWith('Wikipedia talk:Articles for creation/')) {
work_area.append({
type: 'checkbox',
list: [ {
label: 'Move to draft namespace',
name: 'movetodraft',
value: 'movetodraft',
checked: true
} ]
});
}
} else if (e.target.value === 'decline') {
work_area = new Morebits.quickForm.element({
type: 'field',
label: 'Decline request',
name: 'work_area'
});
}
var template_responses = work_area.append({
type: 'select',
label: 'Select a template response: ',
name: 'template',
event: rfud.responseTemplateChanged
});
$.each(rfud.template_responses[e.target.value], function(i, el) {
template_responses.append({
type: 'option',
value: i,
label: (i ? (i + ': ') : '') + el,
selected: /^(Done|Not done)$/.test(el)
});
});
work_area.append({
type: 'textarea',
label: 'Comments',
tooltip: 'Any comments in addition to the template response',
name: 'comments'
});
var old_area = form.work_area;
var result = work_area.render();
old_area.replaceWith(result);
};
rfud.template_responses = {
accept: {
'' : "No template response",
'{{UND|done}}' : "Done",
'{{UND|prod}}' : "contested proposed deletion",
'{{UND|g13}}' : "draft deleted under G13",
'{{UND|afc}}' : "for G13s where {{AFC submission}} was used and the draft was submitted and declined",
'{{UND|afc-ns}}' : "for G13s where {{AFC submission}} was used and where the draft was never submitted",
'{{UND|g13-draft}}' : "for G13s of draft namespace pages never part of the AfC process",
'{{UND|userfy}}' : "Userfied",
'{{UND|userA7}}' : "Userfied A7 article, contact admin before moving back" // has subgroup
},
decline: {
'' : "No template response",
'{{UND|notdone}}' : "Not done",
'{{UND|notdone2}}' : "Not done and will not be done",
'{{UND|2nd}}' : "Was undeleted once, not worked on (soft-decline)",
'{{UND|doesnotexist}}' : "No deleted page with this name",
'{{UND|notdonecompany}}' : "Company article failing NCORP",
'{{UND|notdoneperson}}' : "Biographical article failing NBIO",
'{{UND|inappropriate}}': "Inappropriate topic for Wikipedia",
'{{UND|g11}}' : "Blatant advertisement",
'{{UND|discussion}}' : "Article deleted at a discussion", // has subgroup
'{{UND|csd}}' : "Article deleted per CSD criteria", // has subgroup
'{{UND|copyvio}}' : "Copyright violation" // has subgroup
}
};
rfud.responseTemplateChanged = function(e) {
var template = e.target.value;
var newInput;
if (template === '{{UND|discussion}}') {
newInput = new Morebits.quickForm.element({
type: 'input',
label: 'Discussion: ',
name: 'discussion',
size: '70px',
className: 'UNDtemplateinput'
});
newInput.append({
type: 'input',
label: 'Closing admin: ',
name: 'closingadmin',
className: 'UNDtemplateinput'
});
} else if (template === '{{UND|csd}}' || template === '{{UND|userA7}}') {
newInput = new Morebits.quickForm.element({
type: 'input',
label: 'Deleting admin: ',
name: 'deletingadmin',
className: 'UNDtemplateinput'
});
} else if (template === '{{UND|copyvio}}') {
newInput = new Morebits.quickForm.element({
type: 'input',
label: 'Copyvio source: ',
name: 'copyviosource',
size: '70px',
className: 'UNDtemplateinput'
});
}
if (template === '{{UND|userfy}}' || template === '{{UND|userA7}}') {
if (e.target.form.userfy.checked === false) {
e.target.form.userfy.click();
}
}
$('.UNDtemplateinput').remove();
if (newInput) {
$(e.target.form).find('h5').before(newInput.render());
}
};
rfud.getResponseWikitext = function(forPreview) {
var templatetext = params.template.replace(/^\{\{/, '{{subst:');
var parameterText = '';
switch (params.template) {
case '{{UND|discussion}}':
parameterText = '|' + params.discussion + '|' + params.closingadmin;
break;
case '{{UND|csd}}':
parameterText = '|' + params.deletingadmin;
break;
case '{{UND|copyvio}}':
parameterText = '|' + params.copyviosource;
break;
case '{{UND|userfy}}':
parameterText = '|' + params['userfy.page'];
break;
case '{{UND|userA7}}':
parameterText = '|' + params['userfy.page'] + '|' + params.deletingadmin;
break;
}
templatetext = templatetext.replace('}}', parameterText + '}}');
if (forPreview) {
var text = (templatetext ? (templatetext + (params.comments ? '\n\n' : '' )) : '') + params.comments + ' ~~~~';
} else {
var text = '\n:' + (templatetext ? (templatetext + (params.comments ? '\n\n:' : '' )) : '') + params.comments + ' ~~~~';
}
return text;
};
rfud.preview = function(result) {
params = {};
$(result).find('input, select, textarea').each(function(_i, e) {
params[e.name] = (e.type === 'checkbox' ? e.checked : e.value);
}); // params is not set fully correctly, but this is ok as the incorrectly set fields are not required in preview
result.previewer.beginRender(rfud.getResponseWikitext(true), "API"); // Force wikitext
};
rfud.evaluate = function(e) {
var form = e.target;
params = {};
params.response = form.response.value; // radio input
$(form).find('input, select, textarea').each(function(_i, e) {
if (e.type === 'radio') return true;
if (e.disabled) return true;
params[e.name] = (e.type === 'checkbox' ? e.checked : e.value);
});
if (!params.template && !params.comments) {
alert('Please select a template response or add a comment');
return;
}
if (params['userfy.page'] && params['userfy.page'].includes('USERNAME')) {
alert('Please replace "USERNAME" with a valid username');
return;
}
// disable submit of this form only, leaving any other open morebits forms untouched
$(form).parent().parent().find('.morebits-dialog-buttons')[0].disabled = true;
Morebits.status.init(form);
// Never getting called for some reason, window doesn't autoclose
Morebits.wiki.actionCompleted.event = function() {
// Morebits.wiki.actionCompleted.notice = "Completed, closing window in a second...";
// Morebits.status.actionCompleted( Morebits.wiki.actionCompleted.notice );
// window.setTimeout(function() {
// $(form).parent().prev().find('a').click(); // click close button
// window.location.hash = rfud.sectionName;
// }, 1000);
};
if (params.response === 'accept') {
var p = new Morebits.wiki.page(pageName, 'Undeleting ' + pageName);
p.setEditSummary(params.logsummary + rfud.advert);
p.undeletePage(rfud.doExtras);
} else {
rfud.addResponse();
}
};
rfud.doExtras = function(e) {
var pageobj = e.parent;
pageobj.getStatusElement().info('Done');
// UNDELETE TALK PAGE
if (params.undeletetalk) {
// code adapted from [[Mediawiki:Gadget-Twinklebatchdelete.js]]
var talkpagename = mw.Title.newFromText(pageName).getTalkPage().getPrefixedText();
var statelem = new Morebits.status('Talk page');
var query = {
'action': 'query',
'prop': 'deletedrevisions',
'drvprop': 'ids',
'drvlimit': 1,
'titles': talkpagename
};
new Morebits.wiki.api('Checking for deleted revisions', query, function talk_page( apiobj ) {
var xml = apiobj.responseXML;
var exists = $(xml).find('page:not([missing])').length > 0;
var delrevs = $(xml).find('rev').attr('revid');
if (!delrevs) {
statelem.info('No deleted revisions found');
return;
}
if (exists) {
statelem.update('Already exists');
return;
}
statelem.unlink();
var talkpage = new Morebits.wiki.page(apiobj.query.titles, "Talk page");
talkpage.setEditSummary('Undeleting [[Help:Talk page|talk page]] of "' + pageName + '"' + rfud.advert);
talkpage.undeletePage();
}, statelem).post();
}
// USERFY
if (params.userfy) {
pageobj = new Morebits.wiki.page(pageName, 'Userfying to ' + params['userfy.page']);
pageobj.setMoveDestination(params['userfy.page']);
pageobj.setMoveSuppressRedirect(params.sredr);
pageobj.setEditSummary('Userfying' + rfud.advert);
pageobj.move(function onUserfySuccess() {
pageobj.getStatusElement().info('Done');
rfud.removeDeletionTags();
}, function onUserfyFailure(e) {
var statelem = pageobj.getStatusElement();
if (e.errorCode === 'articleexists') {
Morebits.wiki.numberOfActionsLeft++; // hold dialog from closing //
var skip_button = Morebits.htmlNode('button', 'Skip move');
skip_button.addEventListener('click', function() {
Morebits.wiki.numberOfActionsLeft--; // allow dialog to close //
statelem.warn('skipped following name conflict');
});
var newUserfy = $('<input>').attr('type', 'text')[0];
var new_button = $('<button>').text('OK').click(function() {
Morebits.wiki.numberOfActionsLeft--;
var newTitle = newUserfy.value;
pageobj.setMoveDestination(newTitle);
pageobj.setMoveSuppressRedirect(params.sredr);
pageobj.move(function() {
statelem.info(['userfied to ' + newTitle + ' instead. ',
Morebits.htmlNode('span', 'Please update your response to reflect the new page name', 'red')]);
});
});
statelem.warn([ 'A user page of that name already exists, enter new user page name or skip ',
newUserfy, new_button[0], skip_button ]);
}
});
}
// MOVE WT:AFC PAGES TO DRAFT: SPACE
if (params.movetodraft) {
pageobj = new Morebits.wiki.page(pageName, 'Moving page to draft namespace');
pageobj.setMoveDestination(pageName.replace('Wikipedia talk:Articles for creation/', 'Draft:'));
pageobj.setEditSummary('Moving to new location for drafts' + rfud.advert);
pageobj.move(function onAfcMoveSuccess() {
pageobj.getStatusElement().info('Done');
rfud.removeDeletionTags();
}, function onAfcMoveFailure(e) {
if (e.errorCode === 'articleexists') {
pageobj.getStatusElement().warn('A draft page of that name already exists, skipping...');
Morebits.wiki.numberOfActionsLeft++; // prevent dialog from closing
Morebits.status.actionCompleted('Completed'); // ?
}
});
}
// REMOVE DELETION TAGS
if (!params.userfy && !params.movetodraft) {
rfud.removeDeletionTags();
}
// ADD RESPONSE AT WP:RFUD
rfud.addResponse();
};
rfud.removeDeletionTags = function() {
var currentPageName = pageName;
if (params.userfy) {
currentPageName = params['userfy.page'];
} else if (params.movetodraft) {
currentPageName = pageName.replace('Wikipedia talk:Articles for creation/', 'Draft:');
}
var pageobj = new Morebits.wiki.page(currentPageName, 'Removing deletion tags from page if any');
pageobj.load(function(pageobj) {
var pageText = pageobj.getPageText();
var statelem = pageobj.getStatusElement();
var newPageText = pageText.replace(
// Regex adapted from [[Mediawiki:Gadget-friendlytag.js]]
new RegExp(
// leading whitespace
'^\\s*' +
// capture template(s)
'(?:((?:\\s*' +
// AfD
'(?:<!--.*AfD.*\\n\\{\\{(?:Article for deletion\\/dated|AfDM).*\\}\\}\\n<!--.*(?:\\n<!--.*)?AfD.*(?:\\s*\\n))?|' + // trailing whitespace/newline needed since this subst's a newline
// CFD
'<!-- BEGIN CFD TEMPLATE -->[\\s\\S]*?<!-- END CFD TEMPLATE -->|' +
// begin template format
'\\{\\{\\s*(?:' +
// CSD
'db|delete|db-.*?|speedy deletion-.*?|di-.*?|' +
// PROD
'(proposed deletion|prod blp|book-prod)\\/dated(?:\\s+\\|(?:concern|user|timestamp|help).*)+|' +
// sometimes under a CSD or AfD
'|salt|proposed deletion endorsed' +
// MFD/FFD
'|mfd|ffd' +
// end main template name
')\\s*' +
// template parameters
'(\\|(?:\\{\\{[^{}]*\\}\\}|[^{}])*)?' +
// end template format
'\\}\\})+' +
// end capture
'(?:\\s*\\n)?)' +
// trailing whitespace
'\\s*)?',
'i'), ''
);
var changed = false;
// RFD
if (/#invoke:RfD/.test(newPageText)) {
newPageText = newPageText.replace(/\{\{.*?#invoke:RfD[\s\S]*?\|content=\n([\s\S]*?)<!-- Don.*?-->\n?\}\}/, '$1');
changed = true;
}
// TFD
else if (/Template for discussion\/dated/.test(newPageText)) {
newPageText = newPageText.replace(/\{\{Template for discussion\/dated.*?(\{\{#invoke:Noinclude.*?\}\})?\}\}/, '');
changed = true;
}
if (changed || newPageText !== pageText) {
pageobj.setPageText(newPageText);
pageobj.setEditSummary('Removing deletion tags after undeletion' + rfud.advert);
pageobj.save();
} else {
statelem.info('None found');
}
});
};
rfud.addResponse = function rfudAddResponse() {
var sectionNumber;
// Get section number by scraping the html of the TOC
var sectionFound = false;
$('.toctext').each(function(_i, e) {
if ( Morebits.string.toUpperCaseFirstChar(e.textContent.replace(/_/g,' ')) === rfud.sectionName ) {
sectionNumber = parseInt(e.previousElementSibling.textContent);
sectionFound = true;
return false; // break
}
});
if (!sectionFound) {
new Morebits.status('Saving response').warn('Unable to find section.');
Morebits.status.printUserText(rfud.getResponseWikitext(true), "Your response is provided below, which you may save manually:");
Morebits.wiki.numberOfActionsLeft++; // prevent dialog from closing //
return;
}
var appendtext = rfud.getResponseWikitext();
var editsummary = '/* ' + rfud.sectionName + ' */ ' + (params.response === 'accept' ? 'Accepting' : 'Declining') + ' request' + rfud.advert;
var rfudpage = new Morebits.wiki.page('Wikipedia:Requests for undeletion', 'Saving response');
rfudpage.setPageSection(sectionNumber);
rfudpage.setAppendText(appendtext);
rfudpage.setEditSummary(editsummary);
rfudpage.setMaxConflictRetries(4); // Account for admins responding to multiple requests simultaneously
rfudpage.append(function(pageobj) {
// Reload the section html
var statelem = pageobj.getStatusElement();
var reloadApi = new Morebits.wiki.api('Done, reloading section', {
action: 'parse',
page: 'Wikipedia:Requests for undeletion',
section: sectionNumber,
}, function onReloadSuccess(apiobj) {
var html = $(apiobj.responseXML).find('text').text().replace(/</g, '<').replace(/>/g, '>');
var header = $($('.mw-headline')[sectionNumber - 1].parentElement);
header.nextUntil('h2').remove();
header.replaceWith($(html));
statelem.info('Done, section reloaded');
}, statelem);
reloadApi.post();
});
};
// Add Accept/Decline button
$('li .sysop-show a').each(function(_i, e) {
var rfudhelperlink_accept = Morebits.htmlNode('a', 'Accept');
rfudhelperlink_accept.href = '#';
rfudhelperlink_accept.className = 'rfud-helper-button rfud-accept';
rfudhelperlink_accept.addEventListener('click', rfud.callback);
var rfudhelperlink_decline = Morebits.htmlNode('a', 'Decline');
rfudhelperlink_decline.href = '#';
rfudhelperlink_decline.className = 'rfud-helper-button rfud-decline';
rfudhelperlink_decline.addEventListener('click', rfud.callback);
e.after(document.createTextNode(' | '), rfudhelperlink_accept,
document.createTextNode(' | '), rfudhelperlink_decline);
});
});
// </nowiki>