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= 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<kmax; 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<list2.length; 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<kmax; 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 != '' ){ $(' '+MarkBlockedPlus.defaultPref( window.mbTipBoxInfoText, 'i' )+' ').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; }