// vim: ts=4 sw=4 et ai
//<nowiki>
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 $( "<li>", { "data-mw-revid": rev.revid, "class": "live-reload-new" } ).append(
"(",
$( "<a>" )
.attr( "href", mw.util.getUrl( "Special:Diff/" + rev.revid ) )
.text( "prev" ),
") ",
$( "<a>" )
.attr( "href", mw.util.getUrl( mw.config.get( "wgPageName" ), { oldid: rev.revid } ) )
.text( rev.timestamp.replace( /[TZ]/g, " " ) ),
$( "<span>", { "class": "history-user" } )
.append( $( "<a>", { "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 ) ),
" ",
$( "<span>", { "class": "history-size mw-diff-bytes" } ).text( rev.size + " bytes" ),
" ",
$( "<span>", {
"class": "mw-diff-bytes mw-plusminus-" + ( bytesDiff > 0 ? "pos" : ( bytesDiff < 0 ? "neg" : "null" ) )
} ).text( bytesDiff ),
" ",
$( "<span>", { "class": "comment" } ).text( "(" + rev.comment + ")" ),
" ",
$( "<span>", { "class": "mw-changeslist-links" } ).append(
$( "<span>" ).append(
$( "<span>", { "class": "mw-history-undo" } ).append(
$( "<a>" )
.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(
$( "<span>" ).append(
$( "<span>", { "class": "mw-rollback-link" } ).append(
$( "<a>" )
.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 $( "<li>", { "class": "live-reload-new", "data-timestamp": item.timestamp } ).append(
formatAbuseLogTimestamp( parseIsoTimestamp( item.timestamp ) ),
": ",
$( "<a>", { "class": "mw-userlink userlink" + ( isAnon ? " mw-anonuserlink" : "" ) } )
.attr( "href", mw.util.getUrl( "Special:Contributions/" + item.user ) )
.text( item.user ),
$( "<span>", { "class": "mw-usertoollinks" } ).append(
" (",
$( "<a>", { "class": "mw-usertoollinks-talk userlink" } ).attr( "href", mw.util.getUrl( "User talk:" + item.user, { "vanarticle": item.title } ) ).text( "talk" ),
")" ),
" triggered ",
$( "<a>" )
.attr( "href", mw.util.getUrl( "Special:AbuseFilter/" + item.filter_id ) )
.text( "filter " + item.filter_id ),
", performing the action \"",
item.action,
"\" on ",
$( "<a>" )
.attr( "href", mw.util.getUrl( item.title ) )
.text( item.title ),
". Actions taken: ",
item.result,
" (",
$( "<a>" )
.attr( "href", mw.util.getUrl( "Special:AbuseLog/" + item.id ) )
.text( "details" ),
" | ",
$( "<a>" )
.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(
$( "<div>" ).append(
$( "<button>" )
.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" );
} ),
" ",
$( "<button>" )
.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 ) );
}
} );
}
} );
}
//</nowiki>