markblocked

Created Diff never expires
25 removals
227 lines
49 additions
249 lines
/*
/*
You can import this gadget to other wikis by using mw.loader.load and specifying the local alias for Special:Contributions. For example:
You can import this gadget to other wikis by using mw.loader.load and specifying the local alias for Special:Contributions. For example:
var markblocked_contributions = 'Special:Contributions';
var markblocked_contributions = 'Special:Contributions';
mw.loader.load('//en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-markblocked.js&bcache=1&maxage=259200&action=raw&ctype=text/javascript');
mw.loader.load('//en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-markblocked.js&bcache=1&maxage=259200&action=raw&ctype=text/javascript');


This gadget will pull the user accounts and IPs from the history page and will strike out the users that are currently blocked.
This gadget will pull the user accounts and IPs from the history page and will strike out the users that are currently blocked.
*/
*/
function markBlocked( container ) {
function markBlocked( container ) {
var ipv6Regex = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;
var ipv6Regex = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;


// Collect all the links in the page's content
// Collect all the links in the page's content
var contentLinks = $( container ).find( 'a' );
var contentLinks = $( container ).find( 'a' );


var mbTooltip = window.mbTooltip || '; blocked ($1) by $2: $3 ($4 ago)';
var mbTooltip = window.mbTooltip || '$1; blocked ($2) by $3: $4 ($5 ago)';


// Get all aliases for user: & user_talk:
// Get all aliases for user: & user_talk:
var userNS = [];
var userNS = [];
for ( var ns in mw.config.get( 'wgNamespaceIds' ) ) {
for ( var ns in mw.config.get( 'wgNamespaceIds' ) ) {
if ( mw.config.get( 'wgNamespaceIds' )[ns] == 2 || mw.config.get( 'wgNamespaceIds' )[ns] == 3 ) {
if ( mw.config.get( 'wgNamespaceIds' )[ns] == 2 || mw.config.get( 'wgNamespaceIds' )[ns] == 3 ) {
userNS.push( mw.util.escapeRegExp(ns.replace( /_/g, ' ' )) + ':' );
userNS.push( mw.util.escapeRegExp(ns.replace( /_/g, ' ' )) + ':' );
}
}
}
}


// Let wikis that are importing this gadget specify the local alias of Special:Contributions
// Let wikis that are importing this gadget specify the local alias of Special:Contributions
if ( window.markblocked_contributions === undefined ) {
if ( window.markblocked_contributions === undefined ) {
window.markblocked_contributions = 'Special:Contributions';
window.markblocked_contributions = 'Special:Contributions';
}
}
// RegExp for all titles that are User:| User_talk: | Special:Contributions/ (for userscripts)
// RegExp for all titles that are User:| User_talk: | Special:Contributions/ (for userscripts)
var userTitleRX = new RegExp( '^(' + userNS.join( '|' ) + '|' + window.markblocked_contributions + '\\/)+([^\\/#]+)$', 'i' );
var userTitleRX = new RegExp( '^(' + userNS.join( '|' ) + '|' + window.markblocked_contributions + '\\/)+([^\\/#]+)$', 'i' );


// RegExp for links
// RegExp for links
// articleRX also matches external links in order to support the noping template
// articleRX also matches external links in order to support the noping template
var articleRX = new RegExp( mw.config.get( 'wgArticlePath' ).replace('$1', '') + '([^#]+)' );
var articleRX = new RegExp( mw.config.get( 'wgArticlePath' ).replace('$1', '') + '([^#]+)' );
var scriptRX = new RegExp( '^' + mw.config.get( 'wgScript' ) + '\\?title=([^#&]+)' );
var scriptRX = new RegExp( '^' + mw.config.get( 'wgScript' ) + '\\?title=([^#&]+)' );


var userLinks = {};
var userLinks = {};
var user, url, ma, pgTitle;
var user, url, ma, pgTitle;




// Find all "user" links and save them in userLinks : { 'users': [<link1>, <link2>, ...], 'user2': [<link3>, <link3>, ...], ... }
// Find all "user" links and save them in userLinks : { 'users': [<link1>, <link2>, ...], 'user2': [<link3>, <link3>, ...], ... }
contentLinks.each( function( i, lnk ) {
contentLinks.each( function( i, lnk ) {
if( $( lnk ).hasClass("mw-changeslist-date") || $( lnk ).parent("span").hasClass("mw-history-undo") || $(lnk).parent("span").hasClass("mw-rollback-link") )
if( $( lnk ).hasClass("mw-changeslist-date") || $( lnk ).parent("span").hasClass("mw-history-undo") || $(lnk).parent("span").hasClass("mw-rollback-link") )
{
{
return;
return;
}
}
url = $( lnk ).attr( 'href' );
url = $( lnk ).attr( 'href' );
if ( !url ) {
if ( !url ) {
return;
return;
}
}
if ( ma = articleRX.exec( url ) ) {
if ( ma = articleRX.exec( url ) ) {
pgTitle = ma[1];
pgTitle = ma[1];
} else if ( ma = scriptRX.exec( url ) ) {
} else if ( ma = scriptRX.exec( url ) ) {
pgTitle = ma[1];
pgTitle = ma[1];
} else {
} else {
return;
return;
}
}
pgTitle = decodeURIComponent( pgTitle ).replace( /_/g, ' ' );
pgTitle = decodeURIComponent( pgTitle ).replace( /_/g, ' ' );
user = userTitleRX.exec( pgTitle );
user = userTitleRX.exec( pgTitle );
if ( !user ) {
if ( !user ) {
return;
return;
}
}
user = user[2];
user = user[2];
if( ipv6Regex.test(user) ) user = user.toUpperCase();
if( ipv6Regex.test(user) ) user = user.toUpperCase();
$( lnk ).addClass( 'userlink' );
$( lnk ).addClass( 'userlink' );
if ( !userLinks[user] ) {
if ( !userLinks[user] ) {
userLinks[user] = [];
userLinks[user] = [];
}
}
userLinks[user].push (lnk );
userLinks[user].push (lnk );
} );
} );




// Convert users into array
// Convert users into array
var users = [];
var users = [];
var ips = [];
for ( var u in userLinks ) {
for ( var u in userLinks ) {
users.push( u );
if ( mw.util.isIPAddress(u) ) {
ips.push( u );
} else {
users.push( u );
}
}
}
if ( users.length === 0 ) {
if ( users.length === 0 && ips.length === 0 ) {
return;
return;
}
}


// API request
// API request
var serverTime, apiRequests = 0;
var serverTime = 0;
var apiRequests = users.length + ips.length;
container.addClass( 'markblocked-loading' );
container.addClass( 'markblocked-loading' );
const api = new mw.Api();
// Split users and IPs since users use the bkusers parameter and IPs use bkip for rangeblock support
while ( users.length > 0 ) {
while ( users.length > 0 ) {
apiRequests++;
api.post( {
$.post(
list: 'blocks',
mw.util.wikiScript( 'api' ) + '?format=json&action=query',
bklimit: 100,
{
bkusers: users.splice( 0, 50 ).join( '|' ),
list: 'blocks',
bkprop: 'user|by|timestamp|expiry|range|reason|restrictions'
bklimit: 100,
// no need for 'id|flags'
bkusers: users.splice( 0, 50 ).join( '|' ),
} ).done( markLinks );
bkprop: 'user|by|timestamp|expiry|reason|restrictions'
}
// no need for 'id|flags'
while ( ips.length > 0 ) {
},
// Scope function to prevent overwriting currentIP because of async
markLinks
(function ( currentIP ) {
);
api.post( {
list: 'blocks',
bklimit: 100,
bkip: currentIP,
bkprop: 'user|by|timestamp|expiry|range|reason|restrictions'
}).done( function(resp, xhr) {
markLinks( resp, xhr, currentIP );
});
})( ips.shift() );
}
}


return; // the end
return; // the end




// Callback: receive data and mark links
// Callback: receive data and mark links
function markLinks( resp, status, xhr ) {
function markLinks( resp, xhr, userLink ) {


serverTime = new Date( xhr.getResponseHeader('Date') );
serverTime = new Date( xhr.getResponseHeader('Date') );
var list, blk, tip, links, lnk;
var list, blk, tip, links, lnk;
if ( !resp || !( list = resp.query ) || !( list = list.blocks ) ) {
if ( !resp || !( list = resp.query ) || !( list = list.blocks ) ) {
return;
return;
}
}


for ( var i = 0; i < list.length; i++ ) {
for ( var i = 0; i < list.length; i++ ) {
blk = list[i];
blk = list[i];
var partial = blk.restrictions && !Array.isArray(blk.restrictions); //Partial block
var partial = blk.restrictions && !Array.isArray(blk.restrictions); // Check if partial block
var rangeblock = blk.rangestart !== blk.rangeend; // Check if range block
if ( /^in/.test( blk.expiry ) ) {
if ( /^in/.test( blk.expiry ) ) {
clss = partial ? 'user-blocked-partial' : 'user-blocked-indef';
clss = partial ? 'user-blocked-partial' : 'user-blocked-indef';
blTime = blk.expiry;
blTime = blk.expiry;
} else {
} else {
clss = partial ? 'user-blocked-partial' : 'user-blocked-temp';
clss = partial ? 'user-blocked-partial' : 'user-blocked-temp';
blTime = inHours ( parseTS( blk.expiry ) - parseTS( blk.timestamp ) );
blTime = inHours ( parseTS( blk.expiry ) - parseTS( blk.timestamp ) );
}
}
tip = mbTooltip;
tip = mbTooltip;
if (partial) {
if (partial) {
tip = tip.replace( 'blocked', 'partially blocked' );
tip = tip.replace( 'blocked', 'partially blocked' );
}
}
tip = tip.replace( '$1', blTime )
if (rangeblock) {
.replace( '$2', blk.by )
tip = tip.replace( 'blocked', 'rangeblocked' );
.replace( '$3', blk.reason )
}
.replace( '$4', inHours ( serverTime - parseTS( blk.timestamp ) ) );

links = userLinks[blk.user];
tip = tip.replace( '$1', blk.user )
.replace( '$2', blTime )
.replace( '$3', blk.by )
.replace( '$4', blk.reason )
.replace( '$5', inHours ( serverTime - parseTS( blk.timestamp ) ) );
links = userLinks[userLink || blk.user];
for ( var k = 0; links && k < links.length; k++ ) {
for ( var k = 0; links && k < links.length; k++ ) {
lnk = $( links[k] );
lnk = $( links[k] );
lnk = lnk.addClass( clss );
lnk = lnk.addClass( clss );
if ( window.mbTipBox ) {
if ( window.mbTipBox ) {
$( '<span class=user-blocked-tipbox>#</span>' ).attr( 'title', tip ).insertBefore( lnk );
$( '<span class=user-blocked-tipbox>#</span>' ).attr( 'title', tip ).insertBefore( lnk );
} else {
} else {
lnk.attr( 'title', lnk.attr( 'title' ) + tip );
lnk.attr( 'title', tip );
}
}
}
}
}
}


if ( --apiRequests === 0 ) { // last response
if ( --apiRequests === 0 ) { // last response
container.removeClass( 'markblocked-loading' );
container.removeClass( 'markblocked-loading' );
$( '#ca-showblocks' ).parent().remove(); // remove added portlet link
$( '#ca-showblocks' ).parent().remove(); // remove added portlet link
}
}


}
}




// --------AUX functions
// --------AUX functions


// 20081226220605 or 2008-01-26T06:34:19Z -> date
// 20081226220605 or 2008-01-26T06:34:19Z -> date
function parseTS( ts ) {
function parseTS( ts ) {
var m = ts.replace( /\D/g, '' ).match( /(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ );
var m = ts.replace( /\D/g, '' ).match( /(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ );
return new Date ( Date.UTC( m[1], m[2]-1, m[3], m[4], m[5], m[6] ) );
return new Date ( Date.UTC( m[1], m[2]-1, m[3], m[4], m[5], m[6] ) );
}
}


function inHours( ms ) { // milliseconds -> "2:30" or 5,06d or 21d
function inHours( ms ) { // milliseconds -> "2:30" or 5,06d or 21d
var mm = Math.floor( ms / 60000 );
var mm = Math.floor( ms / 60000 );
if ( !mm ) {
if ( !mm ) {
return Math.floor( ms / 1000 ) + 's';
return Math.floor( ms / 1000 ) + 's';
}
}
var hh = Math.floor( mm / 60 );
var hh = Math.floor( mm / 60 );
mm = mm % 60;
mm = mm % 60;
var dd = Math.floor( hh / 24 );
var dd = Math.floor( hh / 24 );
hh = hh % 24;
hh = hh % 24;
if ( dd ) {
if ( dd ) {
return dd + ( dd < 10 ? '.' + zz( hh ) : '' ) + 'd';
return dd + ( dd < 10 ? '.' + zz( hh ) : '' ) + 'd';
}
}
return hh + ':' + zz( mm );
return hh + ':' + zz( mm );
}
}


function zz( v ) { // 6 -> '06'
function zz( v ) { // 6 -> '06'
if ( v <= 9 ) {
if ( v <= 9 ) {
v = '0' + v;
v = '0' + v;
}
}
return v;
return v;
}
}
}// -- end of main function
}// -- end of main function


// Start on some pages
// Start on some pages
switch ( mw.config.get( 'wgAction' ) ) {
switch ( mw.config.get( 'wgAction' ) ) {
case 'edit':
case 'edit':
case 'submit':
case 'submit':
break;
break;
default: // 'view', 'history', 'purge', ...
default: // 'view', 'history', 'purge', ...
var maybeAutostart = $.Deferred();
var maybeAutostart = $.Deferred();
if ( window.mbNoAutoStart ) {
if ( window.mbNoAutoStart ) {
var portletLink = mw.util.addPortletLink( 'p-cactions', '', 'XX', 'ca-showblocks' );
var portletLink = mw.util.addPortletLink( 'p-cactions', '', 'XX', 'ca-showblocks' );
$( portletLink ).click( function ( e ) {
$( portletLink ).click( function ( e ) {
e.preventDefault();
e.preventDefault();
maybeAutostart.resolve();
maybeAutostart.resolve();
} );
} );
} else {
} else {
maybeAutostart.resolve();
maybeAutostart.resolve();
}
}


$.when( $.ready, mw.loader.using( 'mediawiki.util' ), maybeAutostart ).then( function() {
$.when( $.ready, mw.loader.using( 'mediawiki.util' ), maybeAutostart ).then( function() {
var firstTime = true;
var firstTime = true;


mw.hook( 'wikipage.content' ).add( function ( container ) {
mw.hook( 'wikipage.content' ).add( function ( container ) {
// On the first call after initial page load, container is mw.util.$content
// On the first call after initial page load, container is mw.util.$content


// Used to limit mainspace activity to just the diff definitions
// Used to limit mainspace activity to just the diff definitions
if ( mw.config.get( 'wgAction' ) === 'view' && mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
if ( mw.config.get( 'wgAction' ) === 'view' && mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
container = container.find( '.diff-title' );
container = container.find( '.diff-title' );
}
}


if ( firstTime ) {
if ( firstTime ) {
firstTime = false;
firstTime = false;


// On page load, also update the namespace tab
// On page load, also update the namespace tab
container = container.add( '#ca-nstab-user' );
container = container.add( '#ca-nstab-user' );


mw.util.addCSS('\
mw.util.addCSS('\
.markblocked-loading a.userlink {opacity:' + ( window.mbLoadingOpacity || 0.85 ) + '}\
.markblocked-loading a.userlink {opacity:' + ( window.mbLoadingOpacity || 0.85 ) + '}\
a.user-blocked-temp {' + ( window.mbTempStyle || 'opacity: 0.7; text-decoration: line-through' ) + '}\
a.user-blocked-temp {' + ( window.mbTempStyle || 'opacity: 0.7; text-decoration: line-through' ) + '}\
a.user-blocked-indef {' + ( window.mbIndefStyle || 'opacity: 0.4; font-style: italic; text-decoration: line-through' ) + '}\
a.user-blocked-indef {' + ( window.mbIndefStyle || 'opacity: 0.4; font-style: italic; text-decoration: line-through' ) + '}\
a.user-blocked-partial {' + ( window.mbPartialStyle || 'text-decoration: underline; text-decoration-style: dotted' ) + '}\
a.user-blocked-partial {' + ( window.mbPartialStyle || 'text-decoration: underline; text-decoration-style: dotted' ) + '}\
.user-blocked-tipbox {' + ( window.mbTipBoxStyle || 'font-size:smaller; background:#FFFFF0; border:1px solid #FEA; padding:0 0.3em; color:#AAA' ) + '}\
.user-blocked-tipbox {' + ( window.mbTipBoxStyle || 'font-size:smaller; background:#FFFFF0; border:1px solid #FEA; padding:0 0.3em; color:#AAA' ) + '}\
');
');
}
}


markBlocked( container );
markBlocked( container );
} );
} );
} );
} );
}
}