User:Novem Linguae/Scripts/Links.js

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by Novem Linguae (talk | contribs) at 23:55, 30 April 2024 (Undid revision 1221617972 by Novem Linguae (talk)). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <nowiki>

/*
	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
		- 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.

	| skins = minerva, modern, monobook, timeless, vector, vector-2022
*/

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

	async execute() {
		this.addPendingChangesToTopLeft();
		this.pageName = this.mw.config.get( 'wgPageName' );
		this.createBottomLeftMenuContainer();
		this.mw.util.addPortletLink( 'p-links', `/wiki/Special:CentralAuth?target=${ this.usernameURI }`, 'Central auth' );
		// await this.generateLinksForUserSpace();
		// await this.generateLinksForAllNameSpaces();
	}

	async generateLinksForUserSpace() {
		this.username = this.getFirstMatch( this.pageName, /(?:User:|User_talk:)([^/]+).*/ );
		this.userLinks = '';
		if ( this.username ) {
			this.username = 'User:' + this.username;
			this.usernameURI = encodeURIComponent( this.username.replace( /_/g, ' ' ).replace( /^User:/, '' ) );

			this.generateUserSpaceJsCssLinks();
			this.mw.util.addPortletLink( 'p-links', `/wiki/Special:CentralAuth?target=${ this.usernameURI }`, 'Central auth' );
			this.generateUserRightsLinks();
			this.generateRenameLogLinks();
			this.userLinks += `<li><a href="https://meta.wikimedia.org/wiki/Special:Log?page=User%3A${ this.usernameURI }%40global">Global lock log</a></li>`;
			await this.generateTwinkleLogLinks();
			this.userLinks += `<li><a href="https://en.wikipedia.org/wiki/Special:Log?type=pagetriage-curation&subtype=review&user=User%3A${ this.usernameURI }">Page curation log</a></li>`;
		}
	}

	createBottomLeftMenuContainer() {
		this.mw.util.addPortlet( 'p-links', 'More tools', '#p-coll-print_export' );
	}

	generateLinksForAllNameSpaces() {
		let parentName = this.pageName + '/';
		this.allPageLinks = '';
		if ( this.pageName.includes( '/' ) ) {
			parentName = this.getFirstMatch( this.pageName, /^([^/]+\/)/ );
		}
		this.allPageLinks += `<li><a href="/wiki/Special:PrefixIndex/${ parentName }">Subpages</a></li>`;
	}

	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.userLinks += `<li><a href="https://en.wikipedia.org/wiki/${ title }">${ shortTitle }</a></li>`;
		}
	}

	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.userLinks += `<li><a href="https://meta.wikimedia.org/wiki/Special:GlobalRenameProgress?username=${ this.usernameURI }">Rename log 1</a></li>`;
		this.userLinks += `<li><a href="https://meta.wikimedia.org/wiki/Special:Log?type=renameuser&user=&page=${ this.usernameURI }">Rename log 2</a></li>`;
		this.userLinks += `<li><a href="https://en.wikipedia.org/wiki/Special:Log?type=renameuser&user=&page=${ this.usernameURI }%7Eenwiki">Rename log 3</a></li>`;
	}

	generateUserRightsLinks() {
		this.userLinks += `<li><a href="/wiki/Special:Log?type=rights&user=&page=${ this.usernameURI }">User rights log</a></li>`;
		this.userLinks += `<li><a href="https://meta.wikimedia.org/wiki/Special:Log?type=rights&user=&page=${ this.usernameURI }@enwiki">User rights log (meta)</a></li>`;
	}

	/** common.js and similar */
	generateUserSpaceJsCssLinks() {
		this.userLinks += `<li><a href="/wiki/${ this.username }/common.js">common.js</a></li>`;
		this.userLinks += `<li><a href="https://meta.wikimedia.org/wiki/${ this.username }/global.js">global.js</a></li>`;
		this.userLinks += `<li><a href="/wiki/${ this.username }/vector.js">vector.js</a></li>`;
		this.userLinks += `<li><a href="/wiki/${ this.username }/common.css">common.css</a></li>`;
	}

	addPendingChangesToTopLeft() {
		this.mw.util.addPortletLink(
			'p-navigation',
			this.mw.util.getUrl( 'Special:PendingChanges' ),
			'Pending changes' // can't put comma here, silent error
		);
	}

	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( '|' )
		} );

		/*
		Example format if exists:

		"66442411": {
			"pageid": 66442411,
			"ns": 2,
			"title": "User:Novem Linguae/CSD log",
			"revisions": [
				{
					"revid": 1091295780,
					"parentid": 1091255744,
					"user": "Novem Linguae",
					"timestamp": "2022-06-03T11:38:00Z",
					"comment": "Logging speedy deletion nomination of [[:Liquorose]]."
				}
			]
		},

		Example format if doesn't exist:

		"-1": {
			"ns": 2,
			"title": "User:Jmcclaskey54/CSD log",
			"missing": ""
		},
		*/
		response = response.query.pages;
		const pages = [];
		for ( const key in response ) {
			// the Number class will convert any non-numbers to zero
			if ( Number( key ) > 0 ) {
				pages.push( response[ key ].title );
			}
		}

		return pages;
	}
}

$( async function () {
	await ( new Links( mw ) ).execute();
} );

// </nowiki>