// ==================================================================
// 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 ) );