User:Dafootballguy/AfCScript.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 code will be executed when previewing this page.
This user script seems to have a documentation page at User:Dafootballguy/AfCScript.
/**
* Name: AfC Sorter & Size Marker (Global Sorting & Drafts Only)
* Description: Fetches submission sizes via MediaWiki API, labels them, and allows global sorting across the queue.
* Scope: MediaWiki / Wikipedia
*/
(function () {
'use strict';
if (typeof mw === 'undefined') return;
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () {
$(document).ready(function () {
createSorterUI();
fetchAndMarkSubmissionSizes();
});
});
function createSorterUI() {
if ($('#afc-sorter-panel').length || $('#p-afc-sorter').length) return;
const panelHTML = `
<div id="afc-sorter-panel" style="
display: none;
position: fixed;
bottom: 20px;
right: 20px;
z-index: 99999;
background: #ffffff;
border: 1px solid #a2a9b1;
border-radius: 8px;
padding: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
font-family: sans-serif;
font-size: 14px;
max-width: 280px;
width: 100%;
">
<div style="font-weight: bold; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center;">
<span>AfC Sorter & Size Marker</span>
<div>
<button id="afc-toggle-panel" title="Minimize/Expand" style="background:none; border:none; cursor:pointer; font-size:14px; margin-right:4px;">🔽</button>
<button id="afc-close-panel" title="Close Panel" style="background:none; border:none; cursor:pointer; font-size:14px; font-weight:bold; color:#72777d;">✕</button>
</div>
</div>
<div id="afc-sorter-body">
<div style="margin-bottom: 8px;">
<label style="display:block; font-size:12px; font-weight:bold; color:#54595d; margin-bottom: 4px;">SORT QUEUE BY:</label>
<select id="afc-sort-select" style="width:100%; padding:6px; border-radius:4px; border:1px solid #a2a9b1;" disabled>
<option value="default">Loading draft sizes...</option>
</select>
</div>
<button id="afc-apply-sort" style="
width: 100%;
background: #36c;
color: #fff;
border: none;
padding: 8px;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
" disabled>Apply Sort</button>
<button id="afc-reset-sort" style="
width: 100%;
background: #eaecf0;
color: #202122;
border: none;
padding: 6px;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
margin-top: 6px;
">Reset Order</button>
</div>
</div>
`;
$('body').append(panelHTML);
const portletID = mw.util.addPortletLink(
'p-tb',
'#',
'🔍 AfC Sorter',
't-afc-sorter',
'Open AfC Sorter panel'
);
if (portletID) {
$('#t-afc-sorter a').on('click', function (e) {
e.preventDefault();
$('#afc-sorter-panel').fadeToggle(200);
});
}
$('#afc-toggle-panel').on('click', function () {
$('#afc-sorter-body').toggle();
$(this).text($('#afc-sorter-body').is(':visible') ? '🔽' : '🔼');
});
$('#afc-close-panel').on('click', function () {
$('#afc-sorter-panel').fadeOut(200);
});
$('#afc-apply-sort').on('click', executeSorting);
$('#afc-reset-sort').on('click', resetSorting);
}
function getTargetItems() {
return $('.mw-category-group li, .mw-pages-node li, .mw-category li, .mw-search-results li, .mw-parser-output ul li, .mw-parser-output tr');
}
function fetchAndMarkSubmissionSizes() {
const items = [];
const titles = [];
getTargetItems().each(function () {
const $row = $(this);
if ($row.parents('.printfooter, #mw-navigation, .sidebar, #mw-head, #mw-panel').length) return;
const $link = $row.find('a').first();
const title = $link.attr('title') || $link.text().trim();
const href = $link.attr('href') || '';
const isDraft = title.startsWith('Draft:') || href.includes('Draft:');
if (!isDraft) return;
if (title) {
items.push({ row: $row, title: title });
titles.push(title);
}
});
if (titles.length === 0) {
$('#afc-sort-select').html('<option value="default">No drafts found on page</option>');
return;
}
const api = new mw.Api();
const chunks = [];
for (let i = 0; i < titles.length; i += 50) {
chunks.push(titles.slice(i, i + 50));
}
let processedCount = 0;
chunks.forEach(chunk => {
api.get({
action: 'query',
titles: chunk.join('|'),
prop: 'info',
format: 'json'
}).done(data => {
const pages = data.query && data.query.pages ? data.query.pages : {};
const sizeMap = {};
Object.values(pages).forEach(page => {
if (page.title) {
sizeMap[page.title] = page.length || 0;
}
});
items.forEach(item => {
const size = sizeMap[item.title];
if (size !== undefined) {
item.row.data('afc-size', size);
if (!item.row.find('.afc-size-badge').length) {
let label = '';
if (size < 1500) {
label = 'Very Short';
} else if (size <= 4000) {
label = 'Small';
} else if (size <= 10000) {
label = 'Medium';
} else {
label = 'Large';
}
item.row.append(` <span class="afc-size-badge" style="color: #6c757d; font-size: 11px; margin-left: 6px; font-weight: normal;">[${label}]</span>`);
}
}
});
processedCount += chunk.length;
if (processedCount >= titles.length) {
$('#afc-sort-select').html(`
<option value="default">Default Order</option>
<option value="title-asc">Title (A to Z)</option>
<option value="title-desc">Title (Z to A)</option>
<option value="size-asc">Size (Smallest First)</option>
<option value="size-desc">Size (Largest First)</option>
`).prop('disabled', false);
$('#afc-apply-sort').prop('disabled', false);
}
});
});
}
function executeSorting() {
const selectedSort = $('#afc-sort-select').val();
if (selectedSort === 'default') {
resetSorting();
return;
}
// Collect all valid draft elements globally across the page
const draftItems = [];
getTargetItems().each(function () {
const $row = $(this);
if ($row.parents('.printfooter, #mw-navigation, .sidebar, #mw-head, #mw-panel').length) return;
const $link = $row.find('a').first();
const title = $link.attr('title') || $link.text().trim();
const href = $link.attr('href') || '';
if (title.startsWith('Draft:') || href.includes('Draft:')) {
draftItems.push($row);
}
});
if (draftItems.length === 0) return;
// Sort globally
draftItems.sort(function($a, $b) {
const textA = $a.text().trim();
const textB = $b.text().trim();
if (selectedSort === 'title-asc') {
return textA.localeCompare(textB);
} else if (selectedSort === 'title-desc') {
return textB.localeCompare(textA);
} else if (selectedSort === 'size-asc') {
return ($a.data('afc-size') || 0) - ($b.data('afc-size') || 0);
} else if (selectedSort === 'size-desc') {
return ($b.data('afc-size') || 0) - ($a.data('afc-size') || 0);
}
return 0;
});
// Find or create a unified global container for sorted results
let $container = $('#afc-sorted-container');
if (!$container.length) {
// Hide standard category layout elements to avoid messy fragmentation
$('.mw-category-group, .mw-pages-node').hide();
$container = $('<ul id="afc-sorted-container" style="list-style-type: disc; margin: 1em 0; padding-left: 20px;"></ul>');
$('.mw-content-ltr, #mw-content-text').first().append($container);
} else {
$container.empty();
}
// Append sorted elements globally into the unified container
draftItems.forEach($item => {
// Clone or detach and re-append to move freely
$container.append($item.clone().show());
});
}
function resetSorting() {
$('#afc-sort-select').val('default');
location.reload();
}
})();