User:Barkeep49/rfxCloser.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. |
![]() | Documentation for this user script can be added at User:Barkeep49/rfxCloser. |
(function() {
'use strict';
// Check if the current page is a subpage of RfA or RfB on either test or en wikipedia
const currentHost = window.location.hostname;
if (!(currentHost === 'test.wikipedia.org' || currentHost === 'en.wikipedia.org') ||
!/Wikipedia:Requests_for_(adminship|bureaucratship)\/.+/.test(mw.config.get('wgPageName'))) {
return; // Exit if not on a subpage of RfA or RfB on the allowed wikis
}
// Create the main container
const container = document.createElement('div');
container.id = 'rfx-closer-container';
container.style.cssText = `
position: fixed;
right: 10px;
top: 50%;
transform: translateY(-50%);
width: 300px;
max-height: 80vh;
background: #f8f9fa;
border: 1px solid #a2a9b1;
border-radius: 4px;
z-index: 1000;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
display: none;
`;
// Create the header with close button
const header = document.createElement('div');
header.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: #f8f9fa;
border-bottom: 1px solid #a2a9b1;
position: sticky;
top: 0;
z-index: 1;
`;
const title = document.createElement('h2');
title.textContent = 'RfX Closer';
title.style.cssText = `
margin: 0;
font-size: 1.2em;
color: #202122;
`;
const closeButton = document.createElement('button');
closeButton.textContent = '×';
closeButton.style.cssText = `
background: none;
border: none;
font-size: 1.5em;
cursor: pointer;
color: #54595d;
padding: 0 5px;
`;
closeButton.addEventListener('click', () => {
container.style.display = 'none';
});
header.appendChild(title);
header.appendChild(closeButton);
// Create the content container with scrolling
const contentContainer = document.createElement('div');
contentContainer.style.cssText = `
padding: 15px;
overflow-y: auto;
max-height: calc(80vh - 60px);
`;
// Create the steps container
const stepsContainer = document.createElement('div');
stepsContainer.id = 'rfx-closer-steps';
// Add the container to the page
document.body.appendChild(container);
container.appendChild(header);
container.appendChild(contentContainer);
contentContainer.appendChild(stepsContainer);
// Define the steps
const steps = [
{
title: 'Check Timing',
description: (outcome) => {
const container = document.createElement('div');
container.style.whiteSpace = 'pre-line';
const text = document.createElement('span');
text.textContent = 'Verify that at least 7 days have passed since the listing was made on ';
const link = document.createElement('a');
link.href = '/wiki/Wikipedia:Requests_for_adminship';
link.target = '_blank';
link.textContent = 'Wikipedia:Requests for adminship';
container.appendChild(text);
container.appendChild(link);
return container;
},
completed: false
},
{
title: 'RfA Status',
description: (outcome) => {
const container = document.createElement('div');
container.style.whiteSpace = 'pre-line';
// Create a link to the RFX report
const reportLink = document.createElement('a');
reportLink.href = 'https://en.wikipedia.org/wiki/Wikipedia:Requests_for_adminship';
reportLink.target = '_blank';
reportLink.textContent = 'Check the RFX report for current vote tally and timing information';
container.appendChild(reportLink);
return container;
},
completed: false
},
{
title: 'Verify History',
description: 'Check the history of the transcluded page to ensure comments are genuine and haven\'t been tampered with.',
completed: false
},
{
title: 'Determine Consensus',
description: 'Use traditional rules of thumb and your best judgement to determine consensus. Consider the following:\n- Number of support/oppose votes\n- Quality of arguments\n- Weight of contributors\' opinions\n- Any concerns raised and their resolution',
completed: false
},
{
title: 'Select Outcome',
description: 'Based on the consensus determination, select the appropriate outcome:',
completed: false,
isSelectionStep: true
},
{
title: 'Add Archive Template',
description: (outcome) => {
switch(outcome) {
case 'rfap': return 'Add the successful archive template above the top-level header:\n\n<div class="boilerplate rfa mw-archivedtalk" style="background-color: var(--background-color-success-subtle, #f5fff5); color: var(--color-base, inherit); margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid var(--border-color-success, #aaaaaa);">
:''The following discussion is preserved as an archive of a '''successful''' [[wikipedia:requests for adminship|request for adminship]]. <strong style="color:red">Please do not modify it</strong>.''[[Category:Successful requests for adminship|{{SUBPAGENAME}}]]
';
case 'rfaf': return 'Add the unsuccessful archive template above the top-level header:\n\n<div class="boilerplate rfa mw-archivedtalk" style="background-color: var(--background-color-error-subtle, #fff5f5); color: var(--color-base, #202122); margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid var(--border-color-error, #aaaaaa);">
:''The following discussion is preserved as an archive of a [[wikipedia:requests for adminship|request for adminship]] that '''did not succeed'''. <strong style="color:red">Please do not modify it.</strong>''[[Category:Unsuccessful requests for adminship|{{SUBPAGENAME}}]]
';
case 'rfah': return 'Add the on hold archive template above the top-level header:\n\n<div class="boilerplate metadata rfa mw-archivedtalk" style="background-color: #FFFFE0; margin: 2em 0 0; padding: 0 10px 0 10px; border: 1px solid #AAAAAA;">
:''The following discussion is preserved as a [[Wikipedia:requests for adminship|request for adminship]] that has been {{#ifeq:|yes|automatically placed '''on hold'''|placed '''on hold''' by a [[Wikipedia:Bureaucrats|bureaucrat]]}} pending a decision as to the outcome. <strong style="color:red">Please do not modify the text.</strong> The result of the discussion will be posted soon.''';
default: return 'Select an outcome to see the appropriate template.';
}
},
completed: false,
showFor: ['rfap', 'rfaf', 'rfah']
},
{
title: 'Update Templates',
description: (outcome) => {
return 'Replace the following templates:\n' +
'1. Remove {{rfah}} template\n' +
'2. Remove "Voice your opinion" section\n' +
'3. Replace {{rfatally}} with '''Final <span id="rfatally">(?/?/?)</span>; ended by [[User:Barkeep49|Barkeep49]] ([[User_talk:Barkeep49|talk]]) at 14:52, 14 April 2025 (UTC)''' <!-- Template:finaltally -->\n' +
' - Fill in the template with appropriate vote counts\n' +
' - Include any relevant notes about the discussion';
},
completed: false,
showFor: ['rfap', 'rfaf']
},
{
title: 'Process Promotion',
description: (outcome) => {
const container = document.createElement('div');
container.style.whiteSpace = 'pre-line';
const text = document.createElement('span');
text.textContent = 'If consensus is positive:\n' +
'1. Go to ';
const userrightsLink = document.createElement('a');
userrightsLink.href = '/wiki/Special:Userrights';
userrightsLink.target = '_blank';
userrightsLink.textContent = 'Special:Userrights';
const middleText = document.createElement('span');
middleText.textContent = '\n2. Add sysop user rights\n' +
'3. Remove any redundant userrights\n' +
'4. Reference the RfA in the promotion\n' +
'5. Refer to ';
const listGroupLink = document.createElement('a');
listGroupLink.href = '/wiki/Special:ListGroupRights';
listGroupLink.target = '_blank';
listGroupLink.textContent = 'Special:ListGroupRights';
const endText = document.createElement('span');
endText.textContent = ' for included rights';
container.appendChild(text);
container.appendChild(userrightsLink);
container.appendChild(middleText);
container.appendChild(listGroupLink);
container.appendChild(endText);
return container;
},
completed: false,
showFor: ['rfap']
},
{
title: 'Update Lists',
description: (outcome) => {
const container = document.createElement('div');
container.style.whiteSpace = 'pre-line';
if (outcome === 'rfap') {
const text1 = document.createElement('span');
text1.textContent = '1. Remove the request from ';
const link1 = document.createElement('a');
link1.href = '/wiki/Wikipedia:Requests_for_adminship';
link1.target = '_blank';
link1.textContent = 'Wikipedia:Requests for adminship';
const text2 = document.createElement('span');
text2.textContent = '\n\nFor successful nominations:\n- Add to ';
const link2 = document.createElement('a');
link2.href = '/wiki/Wikipedia:Successful_requests_for_adminship';
link2.target = '_blank';
link2.textContent = 'Wikipedia:Successful requests for adminship';
const text3 = document.createElement('span');
text3.textContent = '\n- Update the relevant counts';
container.appendChild(text1);
container.appendChild(link1);
container.appendChild(text2);
container.appendChild(link2);
container.appendChild(text3);
} else if (outcome === 'rfaf') {
const text1 = document.createElement('span');
text1.textContent = '1. Remove the request from ';
const link1 = document.createElement('a');
link1.href = '/wiki/Wikipedia:Requests_for_adminship';
link1.target = '_blank';
link1.textContent = 'Wikipedia:Requests for adminship';
const text2 = document.createElement('span');
text2.textContent = '\n\nFor unsuccessful nominations:\n- Add to ';
const linkChronological = document.createElement('a');
linkChronological.href = '/wiki/Wikipedia:Unsuccessful_adminship_candidacies_(Chronological)';
linkChronological.target = '_blank';
linkChronological.textContent = 'Wikipedia:Unsuccessful adminship candidacies (Chronological)';
const text3 = document.createElement('span');
text3.textContent = '\n- Add to ';
const linkAlphabetical = document.createElement('a');
linkAlphabetical.href = '/wiki/Wikipedia:Unsuccessful_adminship_candidacies_(Alphabetical)';
linkAlphabetical.target = '_blank';
linkAlphabetical.textContent = 'Wikipedia:Unsuccessful adminship candidacies (Alphabetical)';
const text4 = document.createElement('span');
text4.textContent = '\n- Update the relevant counts';
container.appendChild(text1);
container.appendChild(link1);
container.appendChild(text2);
container.appendChild(linkChronological);
container.appendChild(text3);
container.appendChild(linkAlphabetical);
container.appendChild(text4);
}
return container;
},
completed: false,
showFor: ['rfap', 'rfaf']
}
];
// Create step elements
steps.forEach((step, index) => {
const stepElement = document.createElement('div');
stepElement.className = 'rfx-closer-step';
stepElement.style.cssText = `
margin-bottom: 15px;
padding: 10px;
border: 1px solid #a2a9b1;
border-radius: 4px;
background: #fff;
display: ${index <= 3 ? 'block' : 'none'};
`;
const title = document.createElement('h3');
title.textContent = `${index + 1}. ${step.title}`;
title.style.cssText = `
margin: 0 0 5px 0;
font-size: 1em;
`;
stepElement.appendChild(title);
if (step.isSelectionStep) {
// Create the description
const description = document.createElement('div');
description.style.cssText = `
margin: 0;
font-size: 0.9em;
color: #54595d;
margin-bottom: 10px;
`;
description.textContent = step.description;
// Create the selector
const templateSelector = document.createElement('select');
templateSelector.id = 'rfx-outcome-selector';
templateSelector.style.cssText = `
width: 100%;
margin: 10px 0;
padding: 5px;
`;
// Add blank default option
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = '-- Select Outcome --';
defaultOption.disabled = true;
defaultOption.selected = true;
templateSelector.appendChild(defaultOption);
const templates = [
{ value: 'rfap', label: 'Successful RfA' },
{ value: 'rfaf', label: 'Unsuccessful RfA' },
{ value: 'rfah', label: 'On hold RfA' }
];
templates.forEach(template => {
const option = document.createElement('option');
option.value = template.value;
option.textContent = template.label;
templateSelector.appendChild(option);
});
templateSelector.addEventListener('change', () => {
const selectedOutcome = templateSelector.value;
// Mark the selection step as completed when an outcome is chosen
step.completed = selectedOutcome !== '';
stepElement.style.background = step.completed ? '#e6f3e6' : '#fff';
steps.forEach((s, i) => {
const stepEl = document.querySelector(`.rfx-closer-step:nth-child(${i + 1})`);
if (stepEl) {
if (i <= 3) {
stepEl.style.display = 'block';
} else {
stepEl.style.display = s.showFor && s.showFor.includes(selectedOutcome) ? 'block' : 'none';
// Update description if it's a function
if (typeof s.description === 'function') {
const descEl = stepEl.querySelector('div');
if (descEl) {
descEl.innerHTML = '';
const descContent = s.description(selectedOutcome);
if (descContent instanceof HTMLElement) {
descEl.appendChild(descContent);
} else {
descEl.textContent = descContent;
}
}
}
}
}
});
});
// Add elements in the correct order
stepElement.appendChild(description);
stepElement.appendChild(templateSelector);
} else {
const description = document.createElement('div');
description.style.cssText = `
margin: 0;
font-size: 0.9em;
color: #54595d;
`;
// Set initial description
if (typeof step.description === 'function') {
const descContent = step.description('');
if (descContent instanceof HTMLElement) {
description.appendChild(descContent);
} else {
description.textContent = descContent;
}
} else {
description.textContent = step.description;
}
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.style.marginRight = '5px';
checkbox.addEventListener('change', () => {
step.completed = checkbox.checked;
stepElement.style.background = step.completed ? '#e6f3e6' : '#fff';
});
stepElement.appendChild(checkbox);
stepElement.appendChild(description);
}
stepsContainer.appendChild(stepElement);
});
// Create launch button in the page toolbar
const launchButton = document.createElement('a');
launchButton.id = 'rfx-closer-launch';
launchButton.textContent = 'RfX Closer';
launchButton.style.cssText = `
display: inline-block;
padding: 0.5em 1em;
background: #36c;
color: white;
text-decoration: none;
border-radius: 3px;
margin-left: 10px;
font-size: 0.9em;
`;
launchButton.addEventListener('click', (e) => {
e.preventDefault();
container.style.display = container.style.display === 'none' ? 'block' : 'none';
});
// Find the page toolbar and add the launch button
const pageTools = document.querySelector('#p-tb ul');
if (pageTools) {
const li = document.createElement('li');
li.appendChild(launchButton);
pageTools.appendChild(li);
}
})();