User:Enterprisey/live-reload.js

// vim: ts=4 sw=4 et ai // if( mw.config.get( "wgAction" ) === "history" || mw.config.get( "wgPageName" ) === "Special:AbuseLog" ) { $.when( mw.loader.using( [ "mediawiki.api", "mediawiki.util" ] ), $.ready ).then( function {        var monthNames = mw.config.get( "wgMonthNames" );        var IP_RGX = /^(([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/; // incorporates https://stackoverflow.com/a/14960927/1757964

function addNew( numNew ) { window.liveReloadCount += numNew; document.title = "(" + window.liveReloadCount + ") " + document.title.replace( /^\(.+?\)\s+?/, "" ); }

// thanks https://stackoverflow.com/a/26434619/1757964 function parseIsoTimestamp( timestamp ) { var dt = timestamp.split( /[: T-]/ ).map( parseFloat ); return new Date( Date.UTC( dt[0], dt[1] - 1, dt[2], dt[3] || 0, dt[4] || 0, dt[5] || 0, 0 ) ); }

function parseAbuseLogTimestamp( timestamp ) { var match = timestamp.match( /^(\d\d):(\d\d),\s+(\d\d?)\s+(\w+)\s+(\d+)/ ); //                           1      2         3         4       5            return new Date( Date.UTC( parseInt( match[5] ), monthNames.indexOf( match[4] ) - 1, parseInt( match[3] ), parseInt( match[1] ), parseInt( match[2] ) ) ); }

function formatAbuseLogTimestamp( dateObj ) { var iso = dateObj.toISOString; // e.g. 2011-10-05T14:48:00.000Z return iso.substring( 11, 13 ) + ":" + iso.substring( 14, 16 ) + ", " + iso.substring( 8, 10 ) + " " + monthNames[parseInt( iso.substring( 5, 7 ) )] + " " + iso.substring( 0, 4 ); }

// A list of every type of page supported by the script, and what to do on them. var CONFIGURATIONS = [ {               enable: function  { return mw.config.get( "wgAction" ) === "history"; }, params: function { return { action: "query", prop: "revisions", titles: mw.config.get( "wgPageName" ).replace( /_/g, " " ), rvprop: "ids|timestamp|user|comment|size", rvendid: parseInt( $( "#pagehistory li" ).get( 0 ).dataset.mwRevid ) + 1, formatversion: "2" };               },                handler: function ( data ) { var revs = data.query.pages[0].revisions; if( !revs ) { return; }                   var i;                    for( i = 0; i < revs.length; i++ ) { if( $( "li[data-mw-revid=" + revs[i].revid + "]" ).length ) { break; }                   }                    revs = revs.slice( 0, i ); if( revs.length ) { addNew( revs.length );

var previousTopEntry = $( "#pagehistory li" ).first; $( "#pagehistory" ).prepend( revs.map( function ( rev, index ) { var previousRevSize = ( index + 1 ) < revs.length ? revs[ index + 1 ].size : parseInt( previousTopEntry.find( ".history-size" ).text.match( /^(\d+|,)+/ )[0].replace( /,/g, "" ) ); var bytesDiff = rev.size - previousRevSize; bytesDiff = ( ( bytesDiff > 0 ) ? "+" : "" ) + bytesDiff; var previousRevid = ( index + 1 ) < revs.length ? revs[ index + 1 ].revid : previousTopEntry.get( 0 ).dataset.mwRevid; return $( "", { "data-mw-revid": rev.revid, "class": "live-reload-new" } ).append(                               "(", $( "" ) .attr( "href", mw.util.getUrl( "Special:Diff/" + rev.revid ) ) .text( "prev" ), ")&emsp;",                               $( "" )                                    .attr( "href", mw.util.getUrl( mw.config.get( "wgPageName" ), { oldid: rev.revid } ) )                                    .text( rev.timestamp.replace( /[TZ]/g, " " ) ),                                $( " ", { "class": "history-user" } )                                    .append( $( "", { "class": "mw-userlink userlink" + ( rev.anon ? " mw-anonuserlink" : "" ) } ) .attr( "href", mw.util.getUrl( rev.anon ? ( "Special:Contributions/" + rev.user ) : ( "User:" + rev.user ) ) ) .text( rev.user ) ),                               " ",                                $( " ", { "class": "history-size mw-diff-bytes" } ).text( rev.size + " bytes" ),                                " ",                                $( " ", { "class": "mw-diff-bytes mw-plusminus-" + ( bytesDiff > 0 ? "pos" : ( bytesDiff < 0 ? "neg" : "null" ) ) } ).text( bytesDiff ),                               " ",                                $( " ", { "class": "comment" } ).text( "(" + rev.comment + ")" ),                                " ",                                $( " ", { "class": "mw-changeslist-links" } ).append( $( " " ).append(                                       $( " ", { "class": "mw-history-undo" } ).append( $( "" ) .attr( "href", mw.util.getUrl( mw.config.get( "wgPageName" ), { action: "edit", undo: rev.revid, undoafter: previousRevid } ) )                                               .text( "undo" ) ) ) )                            ); } ) );

var content = $( revs.map( function ( rev ) { return "li[data-mw-revid='" + rev.revid + "']"; } ).join( "," ) ); mw.hook( "wikipage.content" ).fire( content );

// Calculate the number of consecutive edits made by the most recent editor var numConsecutive = 1; var firstEls = $( "#pagehistory li:lt(10)" ); var firstUser = firstEls[0].querySelector( ".mw-userlink" ).textContent; for( var i = 1; i < 12; i++ ) { if( firstEls[i] && firstEls[i].querySelector( ".mw-userlink" ).textContent === firstUser ) { numConsecutive++; } else { break; }                       }                        var consecutive = numConsecutive > 10 ? "more than 10" : numConsecutive;

// Move the rollback link to the first edit var token = decodeURIComponent( $( ".mw-rollback-link a" ).attr( "href" ).match( /token=(.+)$/ )[1] ); $( ".mw-rollback-link" ).parent.remove; $( "#pagehistory li" ).first.find( ".mw-changeslist-links" ).prepend(                           $( " " ).append( $( " ", { "class": "mw-rollback-link" } ).append(                                   $( "" )                                        .text( "rollback: " + consecutive + " edit" + ( numConsecutive === 1 ? "" : "s" ) )                                        .attr( "href", mw.util.getUrl( mw.config.get( "wgPageName" ), {                                            action: "rollback",                                            from: firstUser,                                            token: token                                        } ) ) ) ) ); }               }            },            {                enable: function  { return mw.config.get( "wgPageName" ) === "Special:AbuseLog" && window.location.search.indexOf( "wpSearchFilter" ) >= 0; }, params: function { var firstEntry = $( "ul" ).first.find( "li" ).first; var timestamp; if( firstEntry.get( 0 ).dataset.timestamp ) { timestamp = parseIsoTimestamp( firstEntry.get( 0 ).dataset.timestamp ); } else { timestamp = parseAbuseLogTimestamp( firstEntry.text ); }                   timestamp.setSeconds( timestamp.getSeconds + 1 ); var filter = decodeURIComponent( window.location.search ).match( /wpSearchFilter=((?:\d+|\|)+)($|&|#)/ )[1]; return { action: "query", list: "abuselog", aflprop: "ids|user|title|action|result|timestamp", aflend: timestamp.toISOString, aflfilter: filter, formatversion: "2", };               },                handler: function ( data ) { var items = data.query.abuselog; if( !items || !items.length ) { return; }                   addNew( items.length ); var newElements = items.map( function ( item ) {

// MediaWiki blocks registration of usernames that look like IPs, so this is safe var isAnon = IP_RGX.test( item.user ); return $( "", { "class": "live-reload-new", "data-timestamp": item.timestamp } ).append(                           formatAbuseLogTimestamp( parseIsoTimestamp( item.timestamp ) ),                            ": ",                            $( "", { "class": "mw-userlink userlink" + ( isAnon ? " mw-anonuserlink" : "" ) } )                                .attr( "href", mw.util.getUrl( "Special:Contributions/" + item.user ) )                                .text( item.user ),                            $( " ", { "class": "mw-usertoollinks" } ).append( " (",                               $( "", { "class": "mw-usertoollinks-talk userlink" } ).attr( "href", mw.util.getUrl( "User talk:" + item.user, { "vanarticle": item.title } ) ).text( "talk" ),                                ")" ),                            " triggered ",                            $( "" )                                .attr( "href", mw.util.getUrl( "Special:AbuseFilter/" + item.filter_id ) )                                .text( "filter " + item.filter_id ),                            ", performing the action \"",                            item.action,                            "\" on ",                            $( "" )                                .attr( "href", mw.util.getUrl( item.title ) )                                .text( item.title ),                            ". Actions taken: ",                            item.result, " (",                           $( "" )                                .attr( "href", mw.util.getUrl( "Special:AbuseLog/" + item.id ) )                                .text( "details" ),                            " | ",                            $( "" )                                .attr( "href", mw.util.getUrl( "Special:AbuseLog/examine/log/" + item.id ) )                                .text( "examine" ),                            ")" );                    } ); $( "ul" ).first.prepend( newElements ); newElements.forEach( function ( e ) { mw.hook( "wikipage.content" ).fire( e ); } ); }           }        ];

var config = CONFIGURATIONS.filter( function ( c ) { return c.enable; } ); if( config.length > 1 ) { throw new Error( "More than one configuration was enabled!" ); }       config = config[0];

function start( intervalInMinutes ) { var api = new mw.Api; function go { api.get( config.params ).then( config.handler ); }

var intervalId = window.setInterval( go, intervalInMinutes * 60 * 1000 ); window.liveReloadCount = 0; mw.util.addCSS( ".live-reload-new { background-color: #cfc; }" ); $( "#mw-history-compare,.mw-specialpage-summary" ).before(               $( " " ).append( $( " " )                       .addClass( "mw-ui-button" ) .text( "Reset live count" ) .click( function {                            window.liveReloadCount = 0;                            document.title = document.title.replace( /^\(.+?\)\s+?/, "" );                            $( ".live-reload-new" ).removeClass( "live-reload-new" );                        } ), " ",                   $( " " )                        .addClass( "mw-ui-button" ) .text( "Disable live count" ) .click( function {                            window.clearInterval( intervalId );                            $( this ).parent.remove;                        } ) )                   .css( { "margin": "0.5em 0" } )            ); }

var link = mw.util.addPortletLink( "p-cactions", "#",           "Live reload (1 min)", "pt-livereload-one-minute",            "live reload this page every minute" ); if( link ) { link.addEventListener( "click", function { start( 1 ); } ); }

var link2 = mw.util.addPortletLink( "p-cactions", "#",           "Live reload (custom)", "pt-livereload-custom",            "live reload this page every X minutes" ); if( link2 ) { link2.addEventListener( "click", function {                var interval = window.prompt( "Interval, in minutes" );                if( interval ) {                    start( parseFloat( interval ) );                }            } ); }   } ); } //