Jump to content

User:Dafootballguy/AfCScript.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/**
 * 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();
    }
})();