User:Eighty5cacao/badAnchorWarning.js

// __NOINDEX__ function defaultPref( cfig, dflt ) { return ( typeof cfig == typeof dflt ? cfig : dflt ); }

function unencodeAnchor( anAnchor ) { var fixedAnchor = anAnchor.replace(       /_/g, ' '      ).replace(        /\.([2-7][0-9A-F])/g, function(x,n){ return String.fromCharCode(parseInt(n,16)); }      ).replace(        /\u007F/g, '.7F'      );

//2 UTF-8 bytes var regex2b = /\.([CD][0-9A-F])\.([89AB][0-9A-F])/, result2b = regex2b.exec( fixedAnchor ); var safetyCounter = 0; while ( result2b !== null && safetyCounter < 255 ) { var byte1 = parseInt( result2b[ 1 ], 16 ); var byte2 = parseInt( result2b[ 2 ], 16 ); var fixedCode = ( ( byte1 & 0x1F ) << 6 ) | ( byte2 & 0x3F ); fixedAnchor = fixedAnchor.replace( regex2b, String.fromCharCode( fixedCode ) ); result2b = regex2b.exec( fixedAnchor ); safetyCounter++; }     //3 UTF-8 bytes var regex3b = /\.E([0-9A-F])\.([89AB][0-9A-F])\.([89AB][0-9A-F])/, result3b = regex3b.exec( fixedAnchor ); /*   _*/ safetyCounter = 0; while ( result3b !== null && safetyCounter < 255 ) { var nibb1 = parseInt( result3b[ 1 ], 16 ); var byte2 = parseInt( result3b[ 2 ], 16 ); var byte3 = parseInt( result3b[ 3 ], 16 ); var fixedCode = ( nibb1 << 12 ) | ( ( byte2 & 0x3F ) << 6 ) | ( byte3 & 0x3F ); fixedAnchor = fixedAnchor.replace( regex3b, String.fromCharCode( fixedCode ) ); result3b = regex3b.exec( fixedAnchor ); safetyCounter++; }

return fixedAnchor; }

function showBadAnchorWarning { var zzAction = mw.config.get( 'wgAction' ); var zzNamespaceNumber = mw.config.get( 'wgNamespaceNumber' );

// not useful when editing nor on special pages if ( !window.location.hash || zzAction != 'view' || zzNamespaceNumber < 0 ) return;

// strip the pound sign var myAnchor = window.location.hash.substr( 1 ); if ( !myAnchor || document.getElementById( myAnchor ) ) return;

var warningLink = 'searchInput'; if     ( document.getElementById( 'searchbox' ) ) { warningLink = 'searchbox'; } else if ( document.getElementById( 'toc' ) ) { warningLink = 'toc'; }

if ( window.BAAutofillSearch === true ) { if ( typeof document.getElementById( warningLink ).value == 'string' ) { document.getElementById( warningLink ).value = unencodeAnchor( myAnchor ); }   else { var jqWarningLink = $( '#' + warningLink ); var myInput = jqWarningLink.find( 'input' ); if ( myInput ) { // avoid overwriting existing values because doing so would change button labels myInput.val( function( index, oldValue ) { return oldValue ? oldValue : unencodeAnchor( myAnchor ) } ); }   }  }

window.BAWarnInSiteSub  = defaultPref( window.BAWarnInSiteSub,   true ); window.BAWarnAsJsMessage = defaultPref( window.BAWarnAsJsMessage, true ); if ( window.BAWarnInSiteSub || window.BAWarnAsJsMessage ) { // ensure valid HTML syntax even if bad characters got into the anchor somehow (not a serious security measure) if ( myAnchor.indexOf( '<' ) != -1 || myAnchor.indexOf( '>' ) != -1 || myAnchor.indexOf( '"' ) != -1 )     myAnchor = 'Invalid_anchor_redacted';

var warningText = ' '; warningText += '(The anchor ' + myAnchor + ' was not found; ';   var templateRegex           = /\.7B\.7B.+\.7D\.7D/g;    var exclPipeTemplateRegex   = /\.7B\.7B\.21\.7D\.7D/g; //MW now implements this as a magic word; still needed?    var equalsTemplateRegex     = /\.7B\.7B\.3D\.7D\.7D/g;    var anchorTemplateRegex     = /\.7B\.7B[Aa]nchor\.7C.+\.7D\.7D/g;    var apostropheTemplateRegex = /\.7B\.7B(?:\.27|[Aa]postrophe)\.7D\.7D/g;    var tlTemplateRegex         = /\.7B\.7B[Tt](?:l[pux]?)?\.7C(.+)\.7D\.7D/g;    var noRedirectTemplateRegex = /\.7B\.7B(?:[Nn]o_redirect|-r)\.7C(.+)\.7D\.7D/g;    if ( templateRegex.test( myAnchor ) ) {      warningText += 'if you edited a ';      var fixedAnchor =    myAnchor.replace( exclPipeTemplateRegex, '.7C' ).replace( equalsTemplateRegex, '.3D' );          fixedAnchor = fixedAnchor.replace( anchorTemplateRegex,  ).replace( apostropheTemplateRegex, '.27' ).replace( /^_+|_+$/g,  );

//Now extract template parameters where needed - XXX this won't work correctly with multiple transclusions of any such template... var tlCall = tlTemplateRegex.exec( fixedAnchor ); var tlParam = ''; if ( tlCall ) tlParam = tlCall[1]; if ( tlParam ) fixedAnchor = fixedAnchor.replace( tlTemplateRegex, '.7B.7B' + tlParam + '.7D.7D' );

var nrCall = noRedirectTemplateRegex.exec( fixedAnchor ); var nrParam = ''; if ( nrCall ) nrParam = nrCall[1]; if ( nrParam ) fixedAnchor = fixedAnchor.replace( noRedirectTemplateRegex, nrParam );

if ( fixedAnchor && ( fixedAnchor != myAnchor ) && document.getElementById( fixedAnchor ) ) { warningText += 'section'; }     else { // don't attempt to fix the anchor if there are templates we don't recognize warningText += 'section'; }     warningText += ', you have encountered a MediaWiki software issue'; }   else { if ( myAnchor.indexOf( '/media/' ) == 0 ) { warningText += 'if you just closed Media Viewer, there is no problem'; }     else if ( myAnchor.indexOf( '.5B.5B' ) != -1 && myAnchor.indexOf( '.5D.5D' ) != -1 ) { // Echo (Notifications) fails to strip wikilink markup and unnecessarily percent-encodes some characters. // XXX: This doesn't handle piped links // XXX: There are probably more such characters to deal with...

fixedAnchor = myAnchor.replace( /(\.5[BD]){2}/g, '' ).replace( /%3A/g, ':' );

warningText += 'if you clicked on a notification, you have encountered a MediaWiki software issue'; if ( fixedAnchor && ( fixedAnchor != myAnchor ) && document.getElementById( fixedAnchor ) ) { warningText += '. You were probably looking for '; warningText += ''; warningText += 'this section'; warningText += ''; }     }      else if ( /\.7C(_|$)/.test( myAnchor ) && document.getElementById( 'ca-addsection' ) ) { warningText += 'if you used a pipe trick in the title of a ';

var lastHeadline = $( 'h2:last-of-type > .mw-headline' ); var lastHeadlineID = ''; if ( lastHeadline && lastHeadline.length > 0 ) lastHeadlineID = lastHeadline.attr( 'id' ); if ( lastHeadlineID ) { warningText += ''; warningText += 'new section'; warningText += ''; }       else { warningText += 'new section'; }

warningText += ', you have encountered a MediaWiki software issue'; }     else { if ( warningLink == 'searchbox' ) { warningText += 'try searching this page\'s archives'; }       else { // TODO: descriptive titles here too, once I rethink whether searchInput is a good default for warningLink warningText += 'please check its spelling and capitalization'; if ( zzNamespaceNumber != 0 ) { warningText += ', or search this page\'s archives if any'; }       }      }    }    warningText += '.)';    warningText += ' ';

if ( window.BAWarnInSiteSub === true ) { // non-WMF wikis hide siteSub by default if ( typeof mw.util.addCSS == 'function' ) { mw.util.addCSS( '#siteSub { display:inline; }' ); }

$( '#siteSub' ).append( warningText ); }   if ( window.BAWarnAsJsMessage === true ) { mw.util.jsMessage( warningText.replace( / id="badanchorwarn-/g, ' id="badanchorwarn-jsmsg-' ) ); } } }

if ( !window.BAWarnManual ) $( showBadAnchorWarning );