User:Novem Linguae/Scripts/Links.js

//

/*	This script adds a left menu below the toolbox called "More tools", and includes some links:

- userspace only - common.js		- global.js		- vector.js		- common.css - global.css - central auth (good for seeing what global permissions people have) - rename log - global lock log - Twinkle CSD log - Twinkle PROD log - Twinkle XfD log - Draftify log - Page curation log

- all namespaces - subpages

This script also adds "Pending changes" to the left main menu.

Skin support - left menu - vector - modern - monobook - timeless - right menu (tools menu) - vector-2022 - not displayed at all - minerva

class Links { constructor( mw ) { this.mw = mw; }

async execute { this.mw.util.addPortletLink( 'p-navigation', this.mw.util.getUrl( 'Special:PendingChanges' ), 'Pending changes' ); this.pageName = this.mw.config.get( 'wgPageName' ); this.createBottomLeftMenuContainer; this.username = this.getFirstMatch( this.pageName, /(?:User:|User_talk:)([^/]+).*/ ); if ( this.username ) { await this.generateUserspaceLinks; }		await this.generateSubpageLink; }

createBottomLeftMenuContainer { // Works as expected in vector, modern, monobook, timeless. Is in right menu instead of left menu in vector-2022. Doesn't show up at all in minerva. // Could fix in those skins by adding it before an existing nearby portlet, then using the p.parentNode.appendChild( p ); trick. this.mw.util.addPortlet( 'p-links', 'More tools', '#p-coll-print_export' ); }

async generateUserspaceLinks { this.username = 'User:' + this.username; this.usernameURI = encodeURIComponent( this.username.replace( /_/g, ' ' ).replace( /^User:/, '' ) );

this.mw.util.addPortletLink( 'p-links', `/wiki/${ this.username }/common.js`, 'common.js' ); this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/${ this.username }/global.js`, 'global.js' ); this.mw.util.addPortletLink( 'p-links', `/wiki/${ this.username }/vector.js`, 'vector.js' ); this.mw.util.addPortletLink( 'p-links', `/wiki/${ this.username }/common.css`, 'common.css' ); this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/${ this.username }/global.css`, 'global.css' ); this.mw.util.addPortletLink( 'p-links', `/wiki/Special:CentralAuth?target=${ this.usernameURI }`, 'Central auth' ); this.mw.util.addPortletLink( 'p-links', `/wiki/Special:Log?type=rights&user=&page=${ this.usernameURI }`, 'User rights log' ); this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:Log?type=rights&user=&page=${ this.usernameURI }@enwiki`, 'User rights log (meta)' );

this.generateRenameLogLinks;

this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:Log?page=User%3A${ this.usernameURI }%40global`, 'Global lock log' );

await this.generateTwinkleLogLinks;

this.mw.util.addPortletLink( 'p-links', `/wiki/Special:Log?type=pagetriage-curation&subtype=review&user=User%3A${ this.usernameURI }`, 'Page curation log' ); }

generateSubpageLink { let parentName = this.pageName + '/'; if ( this.pageName.includes( '/' ) ) { parentName = this.getFirstMatch( this.pageName, /^([^/]+\/)/ ); }		this.mw.util.addPortletLink( 'p-links', `/wiki/Special:PrefixIndex/${ parentName }`, 'Subpages' ); }

async generateTwinkleLogLinks { // twinkle logs (csd, prod, xfd) and draftify log // check if they exist with an API query before adding links const logPages = await this.pagesExist( [			`${ this.username }/CSD log`,			`${ this.username }/PROD log`,			`${ this.username }/XfD log`,			`${ this.username }/Draftify log`		] ); for ( const title of logPages ) { const shortTitle = title.replace( /^.*\//, '' ); this.mw.util.addPortletLink( 'p-links', `/wiki/${ title }`, shortTitle ); }	}

generateRenameLogLinks { // All modern renames seem to be put into both en:Special:Log->User rename log AND meta:Special:Log->User rename log. // One older rename was put only into meta:Special:Log->User rename log. // Another older rename was put only into en:Special:Log->User rename log, and was complicated by the fact that ~enwiki had been added to the end of it. // Spaces vs underscores don't seem to matter. User: or no User: doesn't seem to matter. this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:GlobalRenameProgress?username=${ this.usernameURI }`, 'Rename log 1' ); this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:Log?type=renameuser&user=&page=${ this.usernameURI }`, 'Rename log 2' ); this.mw.util.addPortletLink( 'p-links', `/wiki/Special:Log?type=renameuser&user=&page=${ this.usernameURI }%7Eenwiki`, 'Rename log 3' ); }

getFirstMatch( string, regex ) { const matches = string.match( regex ); if ( matches && matches[ 1 ] ) { return matches[ 1 ]; }		return ''; }

/**		* @param {Array} titles */	async pagesExist( titles ) { const api = new this.mw.Api; let response = await api.get( {			action: 'query',			format: 'json',			prop: 'revisions',			titles: titles.join( '|' )		} ); response = response.query.pages; const pages = []; for ( const key in response ) { // the Number class will convert any non-numbers to 0 // the API will return -1 for non-existent pages // the API will return the page ID for existing pages if ( Number( key ) > 0 ) { pages.push( response[ key ].title ); }		}		return pages; } }

$( async => {	await mw.loader.using( [ 'mediawiki.api' ], async  => { await ( new Links( mw ) ).execute; } ); } );

//