User:Enterprisey/rfa-count-toolbar.js

Source: 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.
// vim: ts=4 sw=4 et ai
( function () {
    var RFA_PG = "Wikipedia:Requests for adminship";

    /**
     * Gets the wikitext of a page with the given title (namespace required).
     */
    function getWikitext( title ) {
        return $.getJSON(
            mw.util.wikiScript( "api" ),
            {
                format: "json",
                action: "query",
                prop: "revisions",
                rvprop: "content",
                rvslots: "main",
                rvlimit: 1,
                titles: title
            }
        ).then( function ( data ) {
            var pageId = Object.keys( data.query.pages )[0];
            if( data.query.pages[pageId].revisions ) {
                return { title: data.query.pages[pageId].title, content: data.query.pages[pageId].revisions[0].slots.main["*"] };
            }
            return {};
        } );
    }    

    /**
     * This function converts any (index-able) iterable into a list.
     */
    function iterableToList( nl ) {
        var len = nl.length;
        var arr = new Array( len );
        for( var i = 0; i < len; i++ ) arr[i] = nl[i];
        return arr;
    }

    function numMatches( re, text ) {
        var count = 0;
        while( re.exec( text ) !== null ) count++;
        return count;
    }

    function wikitextToVoteCounts( pageText ) {

        // Strip struck stuff
        pageText = pageText.replace( /<s>[\s\S]+?<\/s>/g, function ( match ) {

            // If we're striking stuff longer than 50 chars, it's
            // probably a malformed tag (left unclosed, maybe)
            return match.length < 50 ? "" : match;
        } );

        // Strip <ins> tags, because they confuse the parser too
        pageText = pageText.replace( /<ins>([\s\S]+?)<\/ins>/g, "$1" );

        var supIdx = pageText.indexOf( "=====Support=====" ),
            oppIdx = pageText.indexOf( "=====Oppose=====" ),
            ntlIdx = pageText.indexOf( "=====Neutral=====" ),
            gcmIdx = pageText.indexOf( "=====General comments=====" ),
            sections = [
                pageText.substring( supIdx, oppIdx ),
                pageText.substring( oppIdx, ntlIdx ),
                pageText.substring( ntlIdx, gcmIdx ) ];

        var BULLET_RGX = /^\s*#[^#:\*]/mg;
        counts = Array(3);
        for( var i = 0; i < 3; i++ ) {
            counts[i] = sections[i].indexOf( "(UTC)" ) >= 0 ? 
                    numMatches( BULLET_RGX, sections[i] ) : 0;
        }
        return { support: counts[0], oppose: counts[1], neutral: counts[2] };
    }

    function rfaWikitextToLinkLabel( wikitext ) {
        var voteCounts = wikitextToVoteCounts( wikitext );
        return voteCounts.support + "/" + voteCounts.oppose + "/" + voteCounts.neutral;
    }

    $.when(
        mw.loader.using( "mediawiki.util" ),
        $.ready
    ).then( function () {
        return getWikitext( RFA_PG );
    } ).then( function ( rfaWikitext ) {
        var RFA_TPL_RGX = /\{\{(Wikipedia:Requests for adminship\/.+?)\}\}/g;
        var rfaMatches = rfaWikitext.content.match( RFA_TPL_RGX );

        // The first one is always /Header, and the last one is
        // always /bureaucratship
        if( rfaMatches.length > 2 ) {
            var pages = rfaMatches.slice( 1, -1 );
            var wikitexts = pages.map( function ( p ) { return getWikitext( p.slice( 2, -2 ) ); } );
            $.when.apply( $, wikitexts ).then( function () {
                iterableToList( arguments ).forEach( function ( revObj, rfaIdx ) {
                    mw.util.addPortletLink(
                        "p-personal",
                        mw.util.getUrl( revObj.title ),
                        rfaWikitextToLinkLabel( revObj.content ),
                        "pt-rfa-" + rfaIdx,
                        revObj.title,
                        null,
                        "#pt-mytalk"
                    );
                } );
            } );
        }
    } );
} )();