User:SoledadKabocha/markBlockedPlus.js

/* Based on the original markblocked script :ru:MediaWiki:Gadget-markblocked.js

by Alex Smotrov et al., original idea by Kalan

Additional inspiration from User:Equazcion/sysopdetector.js

  • /

var MarkBlockedPlus = {

defaultPref: function ( cfig, dflt ) {

return ( typeof cfig === typeof dflt ? cfig : dflt );

},

// replacement for jQuery's deprecated isArray; name is a historical artifact

hackIsArray: function ( maybeArray ) {

return Array.isArray( maybeArray );

},

// expanded later

}

// TODO: Store the defaulted prefs in MarkBlockedPlus instead of writing them back to window

window.mbShowUnregistered = MarkBlockedPlus.defaultPref( window.mbShowUnregistered, true );

window.mbShowGroups = MarkBlockedPlus.defaultPref( window.mbShowGroups, true );

window.mbShowEditCount = MarkBlockedPlus.defaultPref( window.mbShowEditCount, true );

window.mbShowRegDateAbs = MarkBlockedPlus.defaultPref( window.mbShowRegDateAbs, true );

window.mbRemoveWaitingCSSOnError = MarkBlockedPlus.defaultPref( window.mbRemoveWaitingCSSOnError, true );

window.mbLinkClassifierRedirWarn = MarkBlockedPlus.defaultPref( window.mbLinkClassifierRedirWarn, true );

window.mbLinkClassifierTimeoutHack = MarkBlockedPlus.defaultPref( window.mbLinkClassifierTimeoutHack, true );

MarkBlockedPlus.showRedirectWarning = window.mbLinkClassifierRedirWarn;

// Exposed globally for compatibility with original markblocked

function markBlocked( container ) {

var contribPageNames = [ 'Contributions' ];

function scrapeContribLink( ) {

//something went wrong, so get local alias for "Contributions" from "my contribs" link on top

var mwCont = /:([^\/]+)\//.exec( $( '#pt-mycontris a' ).attr( 'href' ) );

if( mwCont ) { mwCont = mwCont[1]; contribPageNames[0] = mwCont; }

MarkBlockedPlus.reallyMarkBlocked( container, contribPageNames );

}

function getContribNameCallback( r, sts, xhr ) {

if ( !r || !r.query ) { scrapeContribLink( ); return; }

if ( !r.query.specialpagealiases ) { scrapeContribLink( ); return; }

for ( pag in r.query.specialpagealiases ) {

if ( pag.realname == 'Contributions' ) {

if ( pag.aliases ) { contribPageNames = pag.aliases; break; }

}

}

MarkBlockedPlus.reallyMarkBlocked( container, contribPageNames );

}

function getContribNamePanic( xhr, textStatus, errorThrown ) {

//TODO: error reporting

scrapeContribLink( );

}

if ( typeof window.mbLocalContribsName == 'string' ) {

contribPageNames[0] = window.mbLocalContribsName;

MarkBlockedPlus.reallyMarkBlocked( container, contribPageNames );

}

else if ( MarkBlockedPlus.hackIsArray( window.mbLocalContribsName ) ) {

contribPageNames = window.mbLocalContribsName;

MarkBlockedPlus.reallyMarkBlocked( container, contribPageNames );

}

else {

var q = {

format:'json',

action:'query',

meta:'siteinfo',

siprop:'specialpagealiases'

}

$.ajax( {

url:mw.util.wikiScript('api'),

dataType:'json',

type:'POST',

data:q,

rawdata:q,

success:getContribNameCallback,

error:getContribNamePanic

} );

}

}

MarkBlockedPlus.reallyMarkBlocked = function ( container, contribPageNames ) {

//----- start of reallyMarkBlocked

var contentLinks = container ? $( container ).find( 'a' ) : $( '#content a' ).add( '#ca-nstab-user a' );

if ( typeof window.mbTempStyle == 'string' && typeof window.mbTemp2Style != 'string' ) window.mbTemp2Style = window.mbTempStyle;

mw.util.addCSS('\

.user-blocked-temp{' + MarkBlockedPlus.defaultPref(window.mbTempStyle, 'opacity: 0.7; text-decoration: line-through') + '}\

.user-blocked-temp2{' + MarkBlockedPlus.defaultPref(window.mbTemp2Style, 'opacity: 0.7; text-decoration: line-through') + '}\

.user-blocked-indef{' + MarkBlockedPlus.defaultPref(window.mbIndefStyle, 'opacity: 0.4; font-style: italic; text-decoration: line-through') + '}\

.user-blocked-tipbox{' + MarkBlockedPlus.defaultPref(window.mbTipBoxStyle, 'font-size:smaller; background:#FFFFF0; border:1px solid #FEA; padding:0 0.3em; color:#AAA') + '}\

.user-info-tipbox{' + MarkBlockedPlus.defaultPref(window.mbTipBoxInfoStyle, 'font-size:smaller; background:#FFFFF0; border:1px solid #FEA; padding:0 0.3em; color:#AAA') + '}\

')

MarkBlockedPlus.tooltip = MarkBlockedPlus.defaultPref( window.mbTooltip, '; blocked ($1) by $2: $3 ($4 ago)' );

MarkBlockedPlus.tipBoxCharsToTrim = MarkBlockedPlus.defaultPref( window.mbTipBoxCharsToTrim, 2 );

//TODO: Figure out a sane way to let users customize the rest of the tooltip.

//get all aliases for user:, user_talk: and special:

MarkBlockedPlus.userNS = [ ];

var userNonTalkNS = [ ], specialNS = [ ];

var firstSpecialNS = '';

var nIDs = mw.config.get( 'wgNamespaceIds' );

for (var ns in nIDs) {

var colonifiedNS = ns + ':';

var cleanNS = colonifiedNS.replace(/_/g, ' ');

if ( nIDs[ns] == 2 ) {

MarkBlockedPlus.userNS.push( cleanNS );

userNonTalkNS.push( cleanNS );

}

else if ( nIDs[ns] == 3 ) {

MarkBlockedPlus.userNS.push( cleanNS );

}

else if ( nIDs[ns] == -1 ) {

if ( firstSpecialNS === '' ) { firstSpecialNS = colonifiedNS.charAt(0).toUpperCase( ) + colonifiedNS.substr(1); }

specialNS.push( cleanNS );

}

}

var contribNames = contribPageNames;

//RegExp for all titles that are User:| User_talk: | Special:Contributions/ (for userscripts)

var userTitleRX = new RegExp('^'

+ '(' + MarkBlockedPlus.userNS.join('|')

+ '|(?:' + specialNS.join('|') + ')(?:' + contribNames.join('|') + ')\\/'

+ ')'

+ '([^\\/#]+)$', 'i');

//RegExp for links. XXX: Is it safe for us to assume that $1 is always at the end of wgArticlePath?

var wAP = mw.config.get( 'wgArticlePath' ), wS = mw.config.get( 'wgScript' );

var cleanArticlePath = wAP.replace('$1', '');

var articleRX = new RegExp( '^' + cleanArticlePath + '([^#]+)' );

var scriptRX = new RegExp( '^' + wS + '\\?title=([^#&]+)' );

MarkBlockedPlus.userLinks = { };

var url, ma, pgTitle;

//find all "user" links and save them in userLinks : { 'users': [, , ...], 'user2': [, , ...], ... }

contentLinks.each(function(i/* unused */, lnk) {

//exclude links added to user(talk) pages by User:Bility/copySectionLink or built-in MW feature

var $lnk = $( lnk );

var myId = $lnk.attr( 'id' );

if ( myId && /^sectiontitlecopy\d+$/.test( myId ) ) return;

if ( $lnk.hasClass( 'mw-headline-anchor' ) ) return;

url = $lnk.attr( 'href' );

if ( !url ) return;

//XXX personal hack XXX

if (

window.mbShibbocuridleet === true &&

url.indexOf( 'title=' ) != -1 &&

url.indexOf( 'curid=' ) != -1 &&

!( $lnk.hasClass( 'external' ) ) &&

!( $lnk.hasClass( 'extiw' ) )

) {

var fixURL = url.replace( /&curid=\d+/, '' );

if ( fixURL !== url ) {

$lnk.addClass( 'curid-stripped' );

$lnk.attr( 'href', fixURL );

url = fixURL;

}

}

//for compatibility with other scripts which may add redirect=no to links

var redirNoRegex = ( wAP.indexOf( '?' ) == -1 ? /\?redirect=no$/ : /&redirect=no$/ );

url = url.replace( redirNoRegex, '' );

//The case beginning with ? is necessary to avoid these parameters polluting the username.

//The & case is just for consistency (is this needed/useful? hmm)

url = url.replace( /[\?&]vanarticle=[^&]+&noautowarn=(tru|fals)e&vanarticlerevid=\d+$/, '' );

//TODO: There should be an option to add a CSS class

if ( url.charAt(0) != '/' || url.indexOf( 'friendlywelcome=' ) != -1 ) { return; }

else if ( ma = articleRX.exec( url ) ) { pgTitle = ma[1]; }

else if ( ma = scriptRX.exec( url ) ) { pgTitle = ma[1]; }

else { return; }

pgTitle = decodeURIComponent( pgTitle ).replace( /_/g, ' ' );

user = userTitleRX.exec( pgTitle );

if ( !user ) return;

user = user[2];

user = user.replace( /^\s+|\s+$/g, '' );

if ( user == '0' || user == 'newbies' || user.length > 64 ) { $lnk.addClass( 'baduserlink' ); return; }

if ( /[\u0080-\u009F\u00A0\u2000-\u200F\u2028-\u202F\u3000\uE000-\uF8FF\uFFFD]/.test( user ) ) { $lnk.addClass( 'baduserlink' ); return; }

user = user.charAt(0).toUpperCase( ) + user.substr(1);

var doubledPrefix = userTitleRX.exec( user );

if( doubledPrefix ) { $lnk.addClass( 'baduserlink' ); return; }

$lnk.addClass( 'userlink' );

if( !( MarkBlockedPlus.hackIsArray( MarkBlockedPlus.userLinks[user] ) ) ) MarkBlockedPlus.userLinks[user] = [ ];

MarkBlockedPlus.userLinks[user].push( lnk );

//optionally replace userpage redlinks with contributions links

if ( window.mbReplaceUserRedLinksWithContribs === true && $lnk.hasClass( 'new' ) ) {

var userNonTalkNSJoined = userNonTalkNS.join('|');

var userNonTalkTitleRX = new RegExp('^'

+ '(' + userNonTalkNSJoined

+ ')'

+ '([^\\/#]+)$', 'i');

if ( !( userNonTalkTitleRX.test( pgTitle ) ) ) { return; }

// "Special:" "Contributions" "/"

var contribTitlePfx = firstSpecialNS + contribNames[0] + '/';

// "Special:" "Contributions" "/" "user_name"

var contribFullTitle = contribTitlePfx + user.replace( / /g, '_' );

//if we're viewing a contributions page, don't create self links

if ( mw.config.get( 'wgPageName' ) === contribFullTitle ) { return; }

//in all: wgArticlePath-without-$1 Special: Contributions / user_name

var newURL = cleanArticlePath + contribFullTitle;

$lnk.attr( 'href', newURL );

var newTitle = $lnk.attr( 'title' );

if ( newTitle ) {

var userNonTalkPrefixRX = new RegExp('^'

+ '(' + userNonTalkNSJoined

+ ')', 'i');

newTitle = newTitle.replace( userNonTalkPrefixRX, contribTitlePfx );

//XXX: make compatible with non-English wikis

newTitle = newTitle.replace( ' (page does not exist)', ' (no user page)' );

$lnk.attr( 'title', newTitle );

}

$lnk.removeClass( 'new' );

$lnk.addClass( 'userlink-redreplaced' );

}

})

//convert users into array

var users = [ ];

for ( var u in MarkBlockedPlus.userLinks ) { users.push( u ); }

if ( users.length === 0 ) { return; }

//API request

MarkBlockedPlus.apiRequests = 0;

MarkBlockedPlus.waitingCSS = mw.util.addCSS( 'a.userlink {opacity:' + MarkBlockedPlus.defaultPref(window.mbLoadingOpacity, 0.85) + '}' );

while ( users.length > 0 ) {

MarkBlockedPlus.apiRequests++;

var formattedUsers = users.splice(0,50).join('|');

$.post(

mw.util.wikiScript('api') + '?format=json&action=query',

{ list: 'blocks|users',

bklimit: 150, bkusers: formattedUsers, //XXX: I increased this limit from 100...could that cause problems?

bkprop: 'user|by|timestamp|expiry|reason',

uslimit: 51, ususers: formattedUsers, //+1 just to be safe (XXX: why? could this actually cause problems?)

usprop: 'groups|editcount|registration' },

MarkBlockedPlus.markLinks

)

}

return; //done sending API requests

}//-- end of reallyMarkBlocked

//callback: receive data and mark links

MarkBlockedPlus.markLinks = function ( resp, status, xhr ) {

function countRequestAsDone( bSuccess ) {

if( --MarkBlockedPlus.apiRequests == 0 ){ //last response

MarkBlockedPlus.waitingCSS.disabled = ( bSuccess || window.mbRemoveWaitingCSSOnError );

$( '#ca-showblocks' ).remove( ); //remove added portlet link (TODO: only if success?)

}

}

MarkBlockedPlus.wgServerTime = new Date( xhr.getResponseHeader( 'Date' ) );

var list, list2, blk, usr, tip, tip2, links, kmax, lnk, curLinkRW, curLinkOldTitle;

if( !resp ){

if ( window.mbReportApiErrors === true ){

MarkBlockedPlus.waitingCSS.disabled = window.mbRemoveWaitingCSSOnError;

throw new Error('markBlockedPlus: No response from API');

}

else{

countRequestAsDone(false); return;

}

}

if( !(list=resp.query) ){

if ( window.mbReportApiErrors === true ){

MarkBlockedPlus.waitingCSS.disabled = window.mbRemoveWaitingCSSOnError;

var errStr = 'markBlockedPlus: API error';

if ( resp.error ){

errStr += ': code: ' + resp.error.code + ', info: ' + resp.error.info;

}

throw new Error(errStr);

}

else{

countRequestAsDone(false); return;

}

}

else {

list2=list.users;

list=list.blocks;

}

var mbShowRegDate = window.mbShowRegDateAbs || window.mbShowRegDateRel;

var mbUsingNewFeatures = window.mbShowUnregistered || window.mbShowGroups || window.mbShowEditCount || mbShowRegDate;

var mbNewFeaturesValid = mbUsingNewFeatures && list2;

var userNSRX = new RegExp( '^' + '(' + MarkBlockedPlus.userNS.join('|') + ')', 'i' );

if ( list ){

for( var i=0; i

blk = list[i]

if( /^in/.test(blk.expiry) ){

clss = 'user-blocked-indef';

blTime = blk.expiry;

}else{

var rawBlTime = MarkBlockedPlus.parseTS(blk.expiry) - MarkBlockedPlus.parseTS(blk.timestamp);

var blTimeRem = MarkBlockedPlus.parseTS(blk.expiry) - MarkBlockedPlus.wgServerTime;

var timeToCheck = ( window.mbLongThreshIsRemainingTime === true ? blTimeRem : rawBlTime );

if ( typeof window.mbPseudoIndefThreshold == 'number' && timeToCheck >= window.mbPseudoIndefThreshold ) {

clss = 'user-blocked-indef';

}

else {

clss = 'user-blocked-temp';

if ( typeof window.mbLongThreshold == 'number' && timeToCheck >= window.mbLongThreshold ) clss += '2';

}

blTime = MarkBlockedPlus.inHours( rawBlTime );

}

if( blk.reason ) {

var preventive = /(pr(otec|even)t|in case|[ei]nsure)/i.test(blk.reason);

//TODO: uw-compblock blocks should not be considered preventive

if ( /(compr[io]mise|(been|got|was) ?hack|pass[- ]?word|hijack|uw-compblock|taken over)/i.test(blk.reason) ) {

clss += ( preventive ? ' user-blocked-preventcompromise' : ' user-blocked-compromised' );

}

if ( /(wiki[- ]?break|(self|user)[- ]?request|retir(ed|ement|ing))/i.test(blk.reason) && !( /\b(abus|ban|sock)/i.test(blk.reason) ) ) {

clss += ' user-blocked-wikibreakenforce';

}

if ( /decease|ha(d|s|ve) died|pass(ed|ing)? (away|on)|mortem/i.test(blk.reason) ) {

clss += ' user-blocked-deceased';

}

else if ( /is dead/i.test(blk.reason) && preventive ) {

clss += ' user-blocked-deceased';

}

}

if ( blk.user == blk.by ) clss += ' user-blocked-self';

tip = MarkBlockedPlus.tooltip.replace('$1', blTime).replace('$2', blk.by).replace('$3', blk.reason)

.replace('$4', MarkBlockedPlus.inHours( MarkBlockedPlus.wgServerTime - MarkBlockedPlus.parseTS(blk.timestamp) ) );

links = MarkBlockedPlus.userLinks[blk.user];

kmax = ( links === undefined ? 0 : links.length ); //TODO: add error reporting

for (var k=0; k

lnk = $(links[k]).addClass(clss);

curLinkRW = '';

curLinkOldTitle = lnk.attr('title') + '';

if( MarkBlockedPlus.showRedirectWarning && !mbNewFeaturesValid && ( lnk.hasClass( 'redirect' ) || lnk.hasClass( 'mw-redirect' ) ) ){

if ( userNSRX.test( MarkBlockedPlus.skipLCAppend( curLinkOldTitle ) ) === false ) {

curLinkRW = '\nBlock log for ' + blk.user + '; redirects outside this wiki\'s user namespaces';

lnk.addClass( 'userlink-redirnonuser' );

}

else if ( MarkBlockedPlus.tipNameDiffers( curLinkOldTitle, blk.user ) ) {

curLinkRW = '\nBlock log for ' + blk.user + '; redirects to other username or IP';

lnk.addClass( 'userlink-redirothername' );

}

}

if( window.mbTipBox === true ){

$(''+MarkBlockedPlus.defaultPref( window.mbTipBoxText, 'B' )+'').attr('title', tip.substr(MarkBlockedPlus.tipBoxCharsToTrim) + curLinkRW).insertBefore(lnk);

}else{

if ( lnk.children( ) ) lnk.children( ).removeAttr( 'title' );

lnk.attr( 'title', curLinkOldTitle + tip + curLinkRW );

}

}

}

}

if ( mbNewFeaturesValid ){

for( var i=0; i

usr = list2[i];

tip2 = '';

if( usr.missing === '' ){

if( window.mbShowUnregistered === true ) tip2 = MarkBlockedPlus.defaultPref( window.mbUnregisteredText, '\nnot registered' )

}

else if( usr.invalid !== '' ){

if ( (window.mbShowGroups === true) && usr.groups ){

tip2 += '\n' + MarkBlockedPlus.remStar( usr.groups );

}

if ( (window.mbShowEditCount === true) && usr.editcount ){

tip2 += '\n' + usr.editcount + ' edit';

if ( usr.editcount != '1' ) tip2 += 's';

if ( mbShowRegDate && usr.registration ){

tip2 += ' since ';

if ( (window.mbShowRegDateAbs === true) && (window.mbShowRegDateRel === true) ){

tip2 += usr.registration + ' (' + MarkBlockedPlus.inHours( MarkBlockedPlus.wgServerTime - MarkBlockedPlus.parseTS(usr.registration) ) + ' ago)';

}

else if ( window.mbShowRegDateAbs === true ){

tip2 += usr.registration;

}

else /* relative only */{

tip2 += MarkBlockedPlus.inHours( MarkBlockedPlus.wgServerTime - MarkBlockedPlus.parseTS(usr.registration) ) + ' ago';

}

}

}

else{

if ( mbShowRegDate && usr.registration ){

tip2 += '\ncreated ';

if ( (window.mbShowRegDateAbs === true) && (window.mbShowRegDateRel === true) ){

tip2 += usr.registration + ' (' + MarkBlockedPlus.inHours( MarkBlockedPlus.wgServerTime - MarkBlockedPlus.parseTS(usr.registration) ) + ' ago)';

}

else if ( window.mbShowRegDateAbs === true ){

tip2 += usr.registration;

}

else /* relative only */{

tip2 += MarkBlockedPlus.inHours( MarkBlockedPlus.wgServerTime - MarkBlockedPlus.parseTS(usr.registration) ) + ' ago';

}

}

}

}

links = MarkBlockedPlus.userLinks[usr.name];

kmax = ( links === undefined ? 0 : links.length ); //TODO: add error reporting

for (var k=0; k

lnk = $(links[k]);

curLinkRW = '';

curLinkOldTitle = lnk.attr('title') + '';

if ( MarkBlockedPlus.showRedirectWarning && ( lnk.hasClass( 'redirect' ) || lnk.hasClass( 'mw-redirect' ) ) ){

if ( userNSRX.test( MarkBlockedPlus.skipLCAppend( curLinkOldTitle ) ) === false ) {

curLinkRW = '\nInfo shown for ' + usr.name + '; redirects outside this wiki\'s user namespaces';

lnk.addClass( 'userlink-redirnonuser' );

}

else if ( MarkBlockedPlus.tipNameDiffers( curLinkOldTitle, usr.name ) ) {

curLinkRW = '\nInfo shown for ' + usr.name + '; redirects to other username or IP';

lnk.addClass( 'userlink-redirothername' );

}

}

if( (window.mbTipBoxInfo === true) && tip2 != '' ){

$('').attr('title', tip2.substr(1) + curLinkRW).insertBefore(lnk)

}else{

if ( lnk.children( ) ) lnk.children( ).removeAttr( 'title' );

lnk.attr( 'title', curLinkOldTitle + tip2 + curLinkRW );

}

if ( usr.missing === '' ) { lnk.addClass( 'userlink-missing' ); }

}

}

}

countRequestAsDone(true);

} //-- end of markLinks

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

//20081226220605 or 2008-01-26T06:34:19Z -> date

MarkBlockedPlus.parseTS = function ( ts ) {

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]) );

}

//milliseconds -> "2:30" or 5d 6h or 21d

MarkBlockedPlus.inHours = function ( ms ) {

var mm = Math.round(ms/60000);

if( !mm ) return Math.round(ms/1000)+'s';

var hh = Math.floor(mm/60); mm %= 60;

var dd = Math.floor(hh/24); hh %= 24;

var yy = Math.floor(dd/365);

if ( yy && ( window.mbShowYears === true ) ){

dd %= 365;

return yy + (dd ? 'yr ' + dd + 'd' : 'yr');

}

else if (dd) return dd + 'd' + ((dd<10 && hh>0)?' '+hh+'h':'');

else return hh + ':' + MarkBlockedPlus.leadZero(mm);

}

//add leading zero to single digits: 6 -> '06'

//was named "zz" in original markblocked

MarkBlockedPlus.leadZero = function ( v ) {

if( v <= 9 ) v = '0' + v;

return v;

}

MarkBlockedPlus.remStar = function ( oldGrps ) {

var cleanGrps = [ ];

for ( var i = 0; i < oldGrps.length; i++ ) {

if ( oldGrps[i] != '*' ) cleanGrps.push( oldGrps[i] );

}

return cleanGrps;

}

MarkBlockedPlus.skipLCAppend = function ( ttip ) {

var myTtip = ttip;

if ( window.LinkClassifierRedirTitleAppend === true ) {

var lcAppendStrToCheck = '\n⤷';

var lcAppendedMsgPos = myTtip.indexOf( lcAppendStrToCheck );

myTtip = myTtip.substr( lcAppendedMsgPos + lcAppendStrToCheck.length );

}

return myTtip;

}

MarkBlockedPlus.tipNameDiffers = function ( ttip, usrnm ) {

var myTtip = MarkBlockedPlus.skipLCAppend( ttip );

var startPos = myTtip.indexOf( ':' );

if ( startPos <= 0 ) return false; //no valid username found - don't show warning

var fragEnd = MarkBlockedPlus.tooltip.indexOf( '$' );

var fragment;

if ( fragEnd == -1 ) {

fragment = MarkBlockedPlus.tooltip;

}

else if ( fragEnd == 0 ) {

//TODO: To handle this case properly, we should pass the actual values of the

//$-parameters into this function. Until then, document that window.mbTooltip

//should not begin with $

fragment = 'This wont' + Math.random( ) + 'match anything';

}

else {

fragment = MarkBlockedPlus.tooltip.substr( 0, fragEnd );

}

var slashPos = myTtip.indexOf( '/' ); if ( slashPos == -1 ) slashPos = myTtip.length;

var anchorPos = myTtip.indexOf( '#' ); if ( anchorPos == -1 ) anchorPos = myTtip.length;

var lineBrkPos = myTtip.indexOf( '\n' ); if ( lineBrkPos == -1 ) lineBrkPos = myTtip.length;

var blkMsgPos = myTtip.indexOf( fragment ); if ( blkMsgPos == -1 ) blkMsgPos = myTtip.length;

var endPos = Math.min( slashPos, anchorPos, lineBrkPos, blkMsgPos );

startPos++;

if ( endPos <= startPos ) return false; //no valid username found - don't show warning

return ( usrnm != myTtip.substr( startPos, endPos - startPos ) );

}

//start on some pages, making sure User:SoledadKabocha/linkclassifier2.js has finished

//NB: As documented, LinkClassifierChainedFunc should be a wrapper function

// that calls importScript on this script, or else we might finish loading before linkclassifier

// does, causing us not to detect the linkclassifier installation

MarkBlockedPlus.setup = function ( ) {

// If the wiki supports ResourceLoader, make sure mw.util has loaded

if ( mw.loader && typeof mw.loader.using === 'function' ) {

mw.loader.using( [ 'mediawiki.util' ], function ( ) {

/* dummy

XXX: this might not be useful as written...

*/

});

}

var linkclassifierDetected = typeof LinkClassifier === 'object';

MarkBlockedPlus.showRedirectWarning =

MarkBlockedPlus.showRedirectWarning && linkclassifierDetected;

//don't really need strict comparisons here

var shouldWaitForLinkClassifier = linkclassifierDetected &&

window.LinkClassifierSupportsFuncChain &&

!window.LinkClassifierOnDemand &&

!window.mbNoAutoStart;

if ( shouldWaitForLinkClassifier ) {

if ( window.mbLinkClassifierTimeoutHack ) {

var wBRT = mw.config.get( 'wgBackendResponseTime' );

if ( typeof wBRT !== 'number' || !isFinite( wBRT ) ) { wBRT = 100; }

else { wBRT = Math.min( Math.max( wBRT, 50 ), 1000 ); }

var rndTOMin = Math.round( Math.sqrt( wBRT ) * Math.log1p( wBRT ) );

var rndTOMax = Math.round( wBRT * Math.E );

var rndTO = rndTOMin + Math.floor( Math.random( ) * ( rndTOMax - rndTOMin + 1 ) );

if ( typeof window.LinkClassifierChainedFunc === 'function' ) {

//Don't overwrite the function if it exists, because it may already have been called.

//It might have been used to import us, after all.

setTimeout( markBlocked, rndTO );

}

else {

window.LinkClassifierChainedFunc = function ( ) {

setTimeout( markBlocked, rndTO );

}

}

}

else {

if ( typeof window.LinkClassifierChainedFunc === 'function' ) {

markBlocked( );

}

else {

window.LinkClassifierChainedFunc = markBlocked;

}

}

}

else

$(function(){

if( window.mbNoAutoStart === true ) {

var plnk = mw.util.addPortletLink( MarkBlockedPlus.defaultPref( window.mbOnDemandLinkLoc, 'p-cactions' ),

'#mb-' + Math.random( ),

MarkBlockedPlus.defaultPref( window.mbOnDemandLinkText, 'XX' ),

'ca-showblocks'

);

$( plnk ).click( function ( e ) {

e.preventDefault( );

markBlocked( );

});

}

else { markBlocked( ); }

})

}

switch ( mw.config.get( 'wgAction' ) ) {

case 'edit':

case 'submit':

if ( window.mbEnableWhenEditing ) { MarkBlockedPlus.setup( ); }

break;

case 'purge':

//shouldn't happen on recent MW; action=purge should redirect (or prompt for confirmation?) rather than showing page content

//just give up

break;

case 'view':

if ( mw.config.get( 'wgNamespaceNumber' ) === 0 && !( window.mbEnableOnMainspaceDiff === true && document.URL.indexOf( 'diff=' ) != -1 ) ) { break; }

//otherwise continue with default

default: //'history', etc.

MarkBlockedPlus.setup( );

}