Участник:Stjn/unformat.js

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
/*
 * Unformat all (most) user links
*/
( () => {
	const mwConfig = mw.config.get( [
		'wgAction',
		'wgArticleId',
		'wgNamespaceIds',
		'wgUserName',
		'wgFormattedNamespaces'
	] );
	if ( mwConfig[ 'wgArticleId' ] === 0 || mwConfig[ 'wgAction' ] === 'history' ) {
		return false;
	}
	
	// Set up support for languages with gendered namespaces (= aliases)
	const getNs = ( id ) => {
		return mwConfig[ 'wgFormattedNamespaces' ][ id ].toLowerCase() + ':';
	};
	const userPrefix = getNs( 2 );
	const userTalkPrefix = getNs( 3 );
	const userNsAliases = Object.keys( mwConfig[ 'wgNamespaceIds' ] ).filter( el => {
		return [ 2, 3 ].includes( mwConfig[ 'wgNamespaceIds' ][ el ] )
	} ).map( el => el.replace( /_/g, ' ' ) );
	
	// Check for valid parent targets
	const inlineTags = [
		'font', 'span',
		'b', 'strong',
		'em', 'i',
		'small',
		'code', 'samp', 'tt'
	]
	function isValidParent( target ) {
		return (
			inlineTags.includes( target.tagName.toLowerCase() )
			&& !target.classList.contains( 'mw-headline' )
		);
	}
	
	// Hacky way to learn how Special:Contributions is called locally
	const getContribsName = () => {
		const defaultName = 'Special:Contributions/';
		const selector = document.querySelector( '#pt-mycontris > a' );
		if ( mw.config[ 'wgUserName' ] === null || selector === null ) return defaultName;
		
		let result = decodeURIComponent( selector.getAttribute( 'href' ) );
		if ( result ) {
			return result.replace( '/wiki/', '' ).split( '/' )[ 0 ] + '/';
		}
		
		return defaultName;
	}
	const localContribsName = getContribsName();
	
	// Does not use RegExp in the hopes it will be somewhat faster
	const isUserLink = ( title ) => {
		if ( !title ) return false;
		
		// Ignore pages in the main namespace
		if ( !title.includes( ':' ) ) return false;
		
		// If the page is Special:Contributions page, exit early
		if ( title.startsWith( localContribsName ) ) return true;
		
		// Ignore the subpages
		if ( title.includes( '/' ) ) return false;
		
		// Check default namespace names first
		title = title.toLowerCase();
		if ( title.startsWith( userPrefix ) || title.startsWith( userTalkPrefix ) ) return true;
		
		let prefix = title.split( ':' )[ 0 ];
		return userNsAliases.includes( prefix );
	}
	
	// .mw-parser-output is here to ignore .diff and other non-content elements
	mw.hook( 'wikipage.content' ).add( function( $content ) {
		var links = $content[ 0 ].querySelectorAll( '.mw-parser-output a' );
		for ( var i = 0; i < links.length; i++ ) {
			var item = links[i];
			var title = item.getAttribute( 'title' );
			
			if ( !isUserLink( title ) ) {
				continue;
			}
			
			if ( item.querySelector( 'img' ) !== null ) {
				continue;
			}
			
			// Remove any styling from link itself
			var text = item.innerText || item.textContent;
			item.textContent = text;
			var parent = item.parentNode;
			
			// Remove parents of user link (probably) with styles
			while ( isValidParent( parent ) ) {
				var grandParent = parent.parentNode;
				var parentText = ( parent.innerText || parent.textContent ).trim();
				
				// Remove styling on an element without class or ID
				if ( parent.classList.length === 0 && parent.id === '' ) {
					if ( parentText.startsWith( text.trim() ) ) {
						// Replace an element with its children
						var fr = document.createDocumentFragment();
						while ( parent.firstChild ) {
							fr.appendChild( parent.firstChild );
						}
						grandParent.replaceChild( fr, parent );
					} else {
						parent.removeAttribute( 'style' );
					}
				}
				
				parent = grandParent;
			}
		}
	} );
} )();