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.
/* If you want to use this script, simply add the following line to your monobook.js:

importScript('User:Anomie/useridentifier.js'); // Linkback: [[User:Anomie/useridentifier.js]]

* (Please keep the comment so I can see how many people use this).
*/

var UserIdentifier = {
    images:{
        '**': 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/77/Wikipedia_svg_logo.svg/20px-Wikipedia_svg_logo.svg.png',
        'abusefilter': 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/64/Wikipedia-Crystal_clear-advancedsetting.png/20px-Wikipedia-Crystal_clear-advancedsetting.png',
        'abusefilter-helper': 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/WikiFilterLogo.png/20px-WikiFilterLogo.png',
        'accountcreator': 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Wikipedia_Accountcreators_v2.svg/20px-Wikipedia_Accountcreators_v2.svg.png',
        'autoreviewer': 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Wikipedia_Autopatrolled.svg/20px-Wikipedia_Autopatrolled.svg.png',
        'bot': 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Crystal_Clear_action_run.png/20px-Crystal_Clear_action_run.png',
        'bureaucrat': 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/Human-preferences-desktop.svg/20px-Human-preferences-desktop.svg.png',
        'checkuser': 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Gnome-searchtool.svg/20px-Gnome-searchtool.svg.png',
        'eventcoordinator': 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c6/Wikipedia_Event_coordinator.svg/20px-Wikipedia_Event_coordinator.svg.png',
        'extendedmover': 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Wikipedia_page_mover.svg/20px-Wikipedia_page_mover.svg.png',
        'filemover': 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Wikipedia_File_mover.svg/20px-Wikipedia_File_mover.svg.png',
        'interface-admin': 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Wikipedia_Interface_administrator.svg/20px-Wikipedia_Interface_administrator.svg.png',
        'massmessage-sender': 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/Wikipedia_mass_messenger.svg/20px-Wikipedia_mass_messenger.svg.png',
        'patroller': 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Wikipedia_New_page_reviewer.svg/20px-Wikipedia_New_page_reviewer.svg.png',
        'reviewer': 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Wikipedia_Reviewer.svg/20px-Wikipedia_Reviewer.svg.png',
        'rollbacker': 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Wikipedia_Rollback.svg/20px-Wikipedia_Rollback.svg.png',
        'suppress': 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/Oversight_logo.png/20px-Oversight_logo.png',
        'sysop': 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Mop.svg/20px-Mop.svg.png',
        'templateeditor': 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Wikipedia_Template_editor_icon_%281%29.svg/20px-Wikipedia_Template_editor_icon_%281%29.svg.png',
        'temporary-account-viewer': 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/TAIV_Wikipedia.svg/20px-TAIV_Wikipedia.svg.png',
    },
    gimages:{
        'steward': 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Wikimedia_Community_Logo.svg/20px-Wikimedia_Community_Logo.svg.png',
        'global-interface-editor': 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/InterfaceEditorIcon.png/20px-InterfaceEditorIcon.png',
        'global-rollbacker': 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Meta-Wiki_Global_rollback-2000px.png/20px-Meta-Wiki_Global_rollback-2000px.png',
        'global-sysop': 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Meta-Wiki_Global_sysop-2000px.png/20px-Meta-Wiki_Global_sysop-2000px.png',
        'global-temporary-account-viewer': 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Global_temporary_account_IP_viewers.svg/20px-Global_temporary_account_IP_viewers.svg.png',
    },

    make_callback: function ( name ) {
        let user = null;
        let globaluserinfo = null;
        let lastedit = null;
        return function ( r ) {
            if ( ! r.query ) {
                mw.log.error('Bad response');
                return;
            }
            if ( r.query.users ) {
                if ( r.query.users.length != 1 ) {
                    mw.log.error('Bad response');
                    return;
                }
                user = r.query.users[0];
            }
            if ( r.query.usercontribs ) {
                lastedit = r.query.usercontribs.length ? r.query.usercontribs[0].timestamp : 'never';
            }
            if ( r.query.globaluserinfo ) {
                globaluserinfo = r.query.globaluserinfo;
            }
            if ( !user || !globaluserinfo || !lastedit ) return;

            if ( user.name != name ) return;
            user.emailable = user.emailable !== undefined;
            const d = document.createElement('div');
            const d2 = document.createElement('div');
            d2.style.display = 'inline-block';
            d2.style.styleFloat = 'left';
            d2.style.overflow = 'visible';
            d2.style.cursor = 'pointer';
            d2.className = 'metadata';
            d2.title = `Registered: ${ user.registration }\nLast edit: ${ lastedit }\nEdits: ${ user.editcount }\nEmailable: ${ user.emailable ? 'yes' : 'no' }\nGender: ${ user.gender }`;
            d2.onclick = function () { d.style.display = d.style.display ? '' : 'none'; };
            d.style.display = 'none';
            d.style.position = 'absolute';
            d.style.background = '#eef';
            d.style.border = '1px solid black';
            d.style.padding = '3px';
            d.style.zIndex = 1000;
            d.appendChild( document.createTextNode( `Registered: ${ user.registration }` ) );
            d.appendChild( document.createElement('br') );
            d.appendChild( document.createTextNode( `Last edit: ${ lastedit }` ) );
            d.appendChild( document.createElement('br') );
            d.appendChild( document.createTextNode( `Edits: ${ user.editcount }` ) );
            d.appendChild( document.createElement('br') );
            d.appendChild( document.createTextNode( `Emailable: ${ user.emailable ? 'yes' : 'no' }` ) );
            d.appendChild( document.createElement('br') );
            d.appendChild( document.createTextNode( `Gender: ${ user.gender }` ) );
            if ( user.groups && user.groups.length > 0 ){
                d.appendChild( document.createElement('br') );
                d.appendChild( document.createTextNode( `Groups: ${ user.groups.join( ', ' ) }` ) );
                for ( const group of user.groups ) {
                    if ( UserIdentifier.images[group] ) {
                        const i = document.createElement('img');
                        i.src = UserIdentifier.images[group];
                        i.width = 20;
                        i.height = 20;
                        i.style.cursor = 'pointer';
                        i.title = group;
                        d2.appendChild( i );
                    }
                }
                d2.title += `\nGroups: ${ user.groups.join( ', ' ) }`;
            }
            if ( globaluserinfo.groups && globaluserinfo.groups.length > 0 ) {
                d.appendChild( document.createElement('br') );
                d.appendChild( document.createTextNode( `Global groups: ${ globaluserinfo.groups.join(', ') }` ) );
                for ( const group of globaluserinfo.groups ) {
                    if ( UserIdentifier.gimages[group] ) {
                        const i = document.createElement('img');
                        i.src = UserIdentifier.gimages[group];
                        i.width = 20;
                        i.height = 20;
                        i.style.cursor = 'pointer';
                        i.title = group;
                        d2.appendChild( i );
                    }
                }
                d2.title += `\nGlobal groups: ${ globaluserinfo.groups.join(', ') }`;
            }
            if ( !d2.firstChild ) {
                const i = document.createElement('img');
                i.src = UserIdentifier.images['**'];
                i.width = 20;
                i.height = 20;
                i.style.cursor = 'pointer';
                d2.appendChild( i );
            }
            const i = document.createElement('span');
            i.style.fontSize = '16px';
            if ( user.gender === 'male' ) {
                i.appendChild( document.createTextNode('♂') );
                i.style.color = '#89CFF0';
            } else if( user.gender === 'female' ) {
                i.appendChild( document.createTextNode('♀') );
                i.style.color = '#F4C2C2';
            }
            if ( i.firstChild ) d2.insertBefore( i, d2.firstChild );
            d.onclick = function () { d.style.display='none'; };
            const h = document.getElementById( 'firstHeading' );
            h.insertBefore( d2, h.firstChild );
            // Sigh, vector 2022 is complicated. This is the best place I could find to insert it without having to override all the fonts and everything.
            const hi = document.querySelector( '.vector-page-toolbar' );
            if( hi ) {
                hi.insertBefore( d, hi.firstChild );
            } else {
                h.parentNode.insertBefore( d, h.nextSibling );
            }
            if ( window.CascadeTopicons ) CascadeTopicons();
        };
    },

    IDUser: name => {
        mw.loader.using( 'mediawiki.util', function () {
            name = decodeURIComponent( name ).replace( /_/g, ' ' );
            const cb = UserIdentifier.make_callback( name );
            $.ajax( {
                url: mw.util.wikiScript('api'),
                dataType: 'json',
                type: 'POST',
                data: {
                    format: 'json',
                    action: 'query',
                    list: 'users',
                    ususers: name,
                    usprop: 'editcount|groups|registration|emailable|gender',
                    meta: 'globaluserinfo',
                    guiuser: name,
                    guiprop: 'groups'
                },
                success: cb,
                error: function ( xhr, textStatus, errorThrown ) {
                    throw new Error('AJAX error: '+textStatus+' '+errorThrown);
                }
            } );
            $.ajax( {
                url: mw.util.wikiScript('api'),
                dataType: 'json',
                type: 'POST',
                data: {
                    format: 'json',
                    action: 'query',
                    list: 'usercontribs',
                    ucuser: name,
                    ucprop: 'timestamp',
                    uclimit: 1
                },
                success: cb,
                error: function( xhr, textStatus, errorThrown ) {
                    throw new Error('AJAX error: '+textStatus+' '+errorThrown);
                }
            } );
            mw.util.addPortletLink( 'p-cactions', `${ mw.util.wikiScript() }?title=Special%3AContributions&target=${ encodeURIComponent( name ) }`, 'Contribs' );
            mw.util.addPortletLink( 'p-cactions', `${ mw.util.wikiScript() }?title=Special%3ACentralAuth/${ encodeURIComponent( name ) }`, 'SUL' );
        } );
    },
 
    onLoad: function () {
        if ( mw.config.get( 'wgNamespaceNumber' ) === 2 || mw.config.get( 'wgNamespaceNumber' ) === 3 ) { 
            let u = mw.config.get( 'wgTitle' );
            const i = u.indexOf( '/' );
            if ( i > 0 ) u = u.substr( 0, i );
            UserIdentifier.IDUser( u );
        } else if( mw.config.get( 'wgCanonicalNamespace' ) === 'Special' && mw.config.get( 'wgCanonicalSpecialPageName' ) == 'Contributions' ) {
            const a = document.querySelector( '#contentSub a' );
            if ( ! a ) return;
            let u = a.href.match( /\/wiki\/User:([^\/]+)/ );
            if ( u ) UserIdentifier.IDUser( u[1] );
            u = a.href.match( /[?&]title=User:([^&]+)/ );
            if ( u ) UserIdentifier.IDUser( u[1] );
        } else if( mw.config.get( 'wgCanonicalNamespace' ) === 'Special' && mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Log' ) {
            let u = [ '', $('#mw-input-user input')[0].defaultValue ];
            if ( ! u[1] ) u = $('#mw-input-page input')[0].defaultValue.match( /^User:([^\/]+)/ );
            if ( u ) UserIdentifier.IDUser( u[1] );
        }
    }
};

$( document ).ready( UserIdentifier.onLoad );