User:Polygnotus/Scripts/EditsPerNamespace.js

// <nowiki> $(document).ready(function() { // Add link to tools menu mw.util.addPortletLink( 'p-tb', '/wiki/Special:Bl

// <nowiki>
$(document).ready(function() {
    // Add link to tools menu
    mw.util.addPortletLink(
        'p-tb',
        '/wiki/Special:BlankPage/UserEditsAnalysis',
        'User Edits Analysis',
        't-user-edits-analysis',
        'Analyze user edits by namespace'
    );
    
    // Customize the page when viewing it
    if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage' && 
        mw.config.get('wgTitle') === 'BlankPage/UserEditsAnalysis') {
        
        document.title = 'User Edits Analysis';
        $('#firstHeading').text('User Edits Analysis');
        
        $('#mw-content-text').html(`
            <div style="max-width: 800px;">
                <p>Enter a username to analyze their edit distribution across namespaces.</p>
                <input type="text" id="username-input" placeholder="Username" style="width: 300px; padding: 5px;">
                <button id="analyze-btn" style="padding: 5px 15px; margin-left: 10px;">Analyze</button>
                <div id="status" style="margin-top: 10px; color: #666;"></div>
                <div id="results" style="margin-top: 20px;"></div>
                <canvas id="chart" width="400" height="400" style="display:none; margin-top: 20px;"></canvas>
            </div>
        `);
        
        $('#analyze-btn').on('click', function() {
            const username = $('#username-input').val().trim();
            if (!username) {
                $('#status').text('Please enter a username.');
                return;
            }
            analyzeUser(username);
        });
        
        $('#username-input').on('keypress', function(e) {
            if (e.which === 13) {
                $('#analyze-btn').click();
            }
        });
    }
});

async function analyzeUser(username) {
    $('#status').text('Fetching edits...');
    $('#results').empty();
    $('#chart').hide();
    
    const namespaces = {};
    let continueToken = null;
    let totalEdits = 0;
    const delay = 1000; // 1 second between requests
    
    try {
        do {
            const params = {
                action: 'query',
                list: 'usercontribs',
                ucuser: username,
                uclimit: 500,
                ucprop: 'title',
                format: 'json',
                maxlag: 5
            };
            
            if (continueToken) {
                params.uccontinue = continueToken;
            }
            
            const response = await $.ajax({
                url: mw.config.get('wgScriptPath') + '/api.php',
                data: params,
                dataType: 'json',
                headers: {
                    'Api-User-Agent': 'UserEditsAnalysis/1.0 (Wikipedia User Script)'
                }
            });
            
            if (response.error) {
                throw new Error(response.error.info);
            }
            
            const contribs = response.query.usercontribs;
            
            for (const contrib of contribs) {
                const title = contrib.title;
                const colonIndex = title.indexOf(':');
                let namespace;
                
                if (colonIndex === -1) {
                    namespace = 'Main';
                } else {
                    const potentialNs = title.substring(0, colonIndex);
                    // Check if it's a valid namespace by checking against known namespaces
                    const nsId = mw.config.get('wgNamespaceIds')[potentialNs.toLowerCase().replace(/ /g, '_')];
                    if (nsId !== undefined) {
                        namespace = potentialNs;
                    } else {
                        namespace = 'Main';
                    }
                }
                
                namespaces[namespace] = (namespaces[namespace] || 0) + 1;
                totalEdits++;
            }
            
            $('#status').text(`Fetched ${totalEdits} edits...`);
            
            continueToken = response.continue ? response.continue.uccontinue : null;
            
            if (continueToken) {
                await new Promise(resolve => setTimeout(resolve, delay));
            }
            
        } while (continueToken);
        
        if (totalEdits === 0) {
            $('#status').text('No edits found for this user.');
            return;
        }
        
        displayResults(namespaces, totalEdits, username);
        
    } catch (error) {
        $('#status').text('Error: ' + error.message);
    }
}

function displayResults(namespaces, totalEdits, username) {
    $('#status').text(`Analysis complete. Total edits: ${totalEdits}`);
    
    // Sort by edit count
    const sorted = Object.entries(namespaces).sort((a, b) => b[1] - a[1]);
    
    let html = '<table style="border-collapse: collapse; width: 100%;">';
    html += '<tr style="background-color: #eaecf0;"><th style="border: 1px solid #a2a9b1; padding: 8px; text-align: left;">Namespace</th>';
    html += '<th style="border: 1px solid #a2a9b1; padding: 8px; text-align: right;">Edits</th>';
    html += '<th style="border: 1px solid #a2a9b1; padding: 8px; text-align: right;">Percentage</th></tr>';
    
    for (const [ns, count] of sorted) {
        const percentage = ((count / totalEdits) * 100).toFixed(2);
        
        // Get namespace ID
        let nsId = 0; // Main namespace
        if (ns !== 'Main') {
            const nsIdLookup = mw.config.get('wgNamespaceIds')[ns.toLowerCase().replace(/ /g, '_')];
            if (nsIdLookup !== undefined) {
                nsId = nsIdLookup;
            }
        }
        
        const contribUrl = mw.util.getUrl('Special:Contributions', {
            target: username,
            namespace: nsId
        });
        
        html += `<tr><td style="border: 1px solid #a2a9b1; padding: 8px;"><a href="${contribUrl}">${ns}</a></td>`;
        html += `<td style="border: 1px solid #a2a9b1; padding: 8px; text-align: right;">${count}</td>`;
        html += `<td style="border: 1px solid #a2a9b1; padding: 8px; text-align: right;">${percentage}%</td></tr>`;
    }
    
    html += '</table>';
    $('#results').html(html);
    
    drawPieChart(sorted, totalEdits);
}

function drawPieChart(data, total) {
    const canvas = document.getElementById('chart');
    const ctx = canvas.getContext('2d');
    
    canvas.style.display = 'block';
    
    const centerX = 200;
    const centerY = 200;
    const radius = 150;
    
    const colors = [
        '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099',
        '#3B3EAC', '#0099C6', '#DD4477', '#66AA00', '#B82E2E',
        '#316395', '#994499', '#22AA99', '#AAAA11', '#6633CC'
    ];
    
    let currentAngle = -Math.PI / 2;
    
    for (let i = 0; i < data.length; i++) {
        const [ns, count] = data[i];
        const sliceAngle = (count / total) * 2 * Math.PI;
        
        ctx.beginPath();
        ctx.moveTo(centerX, centerY);
        ctx.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle);
        ctx.closePath();
        ctx.fillStyle = colors[i % colors.length];
        ctx.fill();
        
        // Add label
        const labelAngle = currentAngle + sliceAngle / 2;
        const labelX = centerX + Math.cos(labelAngle) * (radius * 0.7);
        const labelY = centerY + Math.sin(labelAngle) * (radius * 0.7);
        
        ctx.fillStyle = '#fff';
        ctx.font = 'bold 12px sans-serif';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        
        const percentage = ((count / total) * 100).toFixed(1);
        if (parseFloat(percentage) > 3) { // Only show label if slice is large enough
            ctx.fillText(`${percentage}%`, labelX, labelY);
        }
        
        currentAngle += sliceAngle;
    }
    
    // Add legend
    let legendY = 420;
    for (let i = 0; i < data.length; i++) {
        const [ns, count] = data[i];
        
        ctx.fillStyle = colors[i % colors.length];
        ctx.fillRect(20, legendY, 15, 15);
        
        ctx.fillStyle = '#000';
        ctx.font = '12px sans-serif';
        ctx.textAlign = 'left';
        ctx.fillText(`${ns} (${count})`, 40, legendY + 12);
        
        legendY += 20;
        
        if (legendY > canvas.height - 20) break;
    }
}
// </nowiki>

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.