User:Inductiveload/scan transcludes.js

From Wikisource
Jump to navigation Jump to search
Note: After saving, changes may not occur immediately. Click here to learn how to bypass your browser's cache.
  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Cmd-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (Cmd-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Clear the cache in Tools → Preferences

For details and instructions about other browsers, see Wikipedia:Bypass your cache.

// ==================================================================
// Scan an Index page's childen for transclusion status
//
// Add a tool to the sidebar on Index pages. When activated, each page in the
// page list is checked for transclusion.
//
// If pages are:
//      - transcluded, they are outlined in GREEN
//      - expected to be so, but are not, they are outlined in heavy RED
//      - not expected to be so, and are not, they are outlined in ORANGE
//
// A page is "expected" to transcluded when it is proofread, validated or
// prolematic,
//
// Multiple transclusions of the same page result in a thicker outline.
// ==================================================================

/* eslint-disable one-var, vars-on-top */

( function ( $, mw ) {

	'use strict';

	if ( mw.config.get( 'wgCanonicalNamespace' ) !== 'Index' ) {
		return;
	}

	var ST = {
		styles: {
			ok: 'outline: 1px solid green;',
			multiple: 'outline: 2px solid green;',
			expNot: 'outline: 1px solid orange;',
			warn: 'outline: 2px solid red;'
		},
		exemptCats: [ 'Category:Not transcluded' ]
	};

	var ScanTranscludes = function () {
		this.pagelinkSelector = '.prp-index-pagelist > a';
	};

	ScanTranscludes.prototype.init = function () {

		// console.log("Init ScanTranscludes");

		// only init in the index namespace
		if ( mw.config.get( 'wgNamespaceNumber' ) !== 106 ||
				mw.config.get( 'wgAction' ) !== 'view' ) {
			return;
		}

		this.installPortlet();
	};

	ScanTranscludes.prototype.installPortlet = function () {

		var self = this,

			// var accessKey = "a";
			// self.steal_accesskey(accessKey);

			portlet = mw.util.addPortletLink(
				'p-tb',
				'#',
				'Check transclusion',
				't-check-transcludes',
				'Check page transclusion status (shift-click to clear)'
			// accessKey
			);

		$( portlet ).on( 'click', function ( e ) {
			e.preventDefault();

			if ( e.shiftKey ) {
				self.clearMarking();
			} else {
				self.activate();
			}
		} );
	};

	ScanTranscludes.prototype.activate = function () {
		// console.log("Checking transclusion");

		var self = this,

			// inject style rules
			$style = $( '<style>' );

		for ( var key in ST.styles ) {
			$style.append( '._chk_trans_' + key + ' { ' + ST.styles[ key ] + '}\n' );
		}

		// eslint-disable-next-line no-jquery/no-global-selector
		$( 'html > head' ).append( $style );

		$( this.pagelinkSelector ).each( function ( index, link ) {
			self.processPageLink( $( link ) );
		} );
	};

	/**
	 * Gets the Page title from a link
	 *
	 * @param {jQuery} $link
	 * @return {string} title
	 */
	function getTitleFromLink( $link ) {
		var title = $link.attr( 'title' );

		if ( !title ) {
			return null;
		}

		return title.replace( / \(.*?\)$/, '' );
	}

	/*
	 * Consider problematic, proofread and validated as "should be transcluded"
	 */
	function linkShouldBeTranscluded( link ) {
		return link.hasClass( 'quality2' ) ||
		link.hasClass( 'quality3' ) ||
		link.hasClass( 'quality4' );
	}

	ScanTranscludes.prototype.processPageLink = function ( link ) {
		var self = this,

			title = getTitleFromLink( link );

		// couldn't get a link target
		if ( !title ) {
			return;
		}

		// NOTE: for some reason _every_ page is seen as included on the Index
		// page. Only count transcludes from mainspace.
		new mw.Api().get( {
			action: 'query',
			list: 'embeddedin',
			titles: title,
			prop: 'categories',
			einamespace: 0,
			eititle: title,
			format: 'json',
			formatversion: 2
		} )
			.then( function ( data ) {
				var count = data.query.embeddedin.length;

				// list of cats in the page
				var cats = data.query.pages[ 0 ].categories.map( function ( pcat ) {
					return pcat.title;
				} );

				// any excluded?
				var intersection = ST.exemptCats.filter( function ( exemptCat ) {
					return cats.indexOf( exemptCat ) !== -1;
				} );

				self.decorateLink( link, count, intersection.length > 0 );

				link.data( 'trans_count', count );
			} );
	};

	ScanTranscludes.prototype.decorateLink = function ( link, count, exempt ) {

		var classname = '',
			should = !exempt && linkShouldBeTranscluded( link );

		if ( should ) {
			// red is not, green if yes
			if ( count === 0 ) {
				classname = 'warn';
			} else {
				classname = ( count > 1 ) ? 'multiple' : 'ok';
			}
		} else {
			// orange if not, green if yes
			classname = ( count > 1 ) ? 'ok' : 'expNot';
		}

		// eslint-disable-next-line mediawiki/class-doc
		link.addClass( '_chk_trans_' + classname );
	};

	ScanTranscludes.prototype.clearMarking = function () {
		for ( var key in ST.styles ) {
			// eslint-disable-next-line mediawiki/class-doc
			$( this.pagelinkSelector ).removeClass( '._chk_trans_' + key );
		}
	};

	var st = new ScanTranscludes();
	st.init();

// eslint-disable-next-line no-undef
}( jQuery, mediaWiki ) );