User:Chlod/Scripts/DuplicatedRefs.js

// DuplicatedRefs

// Author: Chlod

// Version: 2.0.1

// Highlight equivalent references which are duplicated in the same paragraph.

// See Special:Diff/1141909502#Ref duplication highlight tool.

mw.loader.using( [ 'mediawiki.util' ], function () {

mw.util.addCSS( '.reference-localduplicated { background-color: #ffff00; }' );

mw.util.addPortletLink(

'p-tb', 'javascript:void', 'Highlight duplicate refs', 't-dupref',

'Highlight all references in the same paragraph which are not interrupted by other references in sequence.'

).addEventListener( 'click', function ( e ) {

e.preventDefault();

let currentReferenceBundle = [];

let lastReferenceBundle = null;

let $lastGrandfatherElement = null;

let duplicatesFound = 0;

var references = document.querySelectorAll( '.mw-body-content .mw-parser-output .reference' );

for ( var item of references ) {

const $item = $( item );

const $grandfatherElement = $item.parents( '.mw-parser-output >' );

const referenceId = $item.find( 'a' ).attr( 'href' );

if ( referenceId == null ) {

// Invalid reference? We'll skip it.

continue;

}

if ( $lastGrandfatherElement == null ) {

// This is only the case if this is the very first reference in the article.

// We'll assign the reference ID as well and move on.

$lastGrandfatherElement = $grandfatherElement;

currentReferenceBundle.push( $item );

continue;

}

if ( !$lastGrandfatherElement.is( $grandfatherElement ) ) {

// Different paragraph/section. Snip bundle.

$lastGrandfatherElement = $grandfatherElement;

lastReferenceBundle = null;

currentReferenceBundle = [];

}

// Checks for the next sibling. The next sibling may be a text node or a DOM element.

const hasNextReference = item.nextSibling instanceof HTMLElement &&

item.nextSibling.classList.contains( 'reference' );

currentReferenceBundle.push( $item );

if ( !hasNextReference ) {

// Next sibling is not a reference. Snip bundle and compare.

// Get the reference IDs and see if they are the same on both bundles.

const bundleReferenceIds = new Set(

currentReferenceBundle.map(

e => e.find( 'a' ).attr( 'href' )

)

);

if ( lastReferenceBundle != null ) {

const lastBundleReferenceIds = new Set(

lastReferenceBundle.map(

e => e.find( 'a' ).attr( 'href' )

)

);

// Check if the two sets have the same values.

// Unordered, and repeating values discarded.

const sameIds = bundleReferenceIds.size == lastBundleReferenceIds.size &&

[...bundleReferenceIds].every( value => lastBundleReferenceIds.has( value ) );

if ( sameIds ) {

// Same IDs. Highlight both bundles.

currentReferenceBundle.forEach( e => e.addClass( 'reference-localduplicated' ) );

lastReferenceBundle.forEach( e => e.addClass( 'reference-localduplicated' ) );

duplicatesFound += currentReferenceBundle.length;

}

}

// Also check for repeated reference within the same bundle.

if ( bundleReferenceIds.size !== currentReferenceBundle.length ) {

// Different IDs, but there might still be repeating references in the same bundle.

const foundReferenceIds = new Set();

const foundDuplicateReferenceIds = new Set();

currentReferenceBundle.forEach( e => {

const foundReferenceId = e.find( 'a' ).attr( 'href' );

if ( foundReferenceIds.has( foundReferenceId ) ) {

// Duplicate found!

foundDuplicateReferenceIds.add( foundReferenceId );

// Afterwards, mark the ID as found (or do nothing if it's already in).

}

// else: no duplicate found, just add it in.

foundReferenceIds.add( foundReferenceId );

} );

currentReferenceBundle.forEach( e => {

if ( foundDuplicateReferenceIds.has( e.find( 'a' ).attr( 'href' ) ) ) {

e.addClass( 'reference-localduplicated' );

}

} );

duplicatesFound += foundDuplicateReferenceIds.size;

}

lastReferenceBundle = currentReferenceBundle;

currentReferenceBundle = [];

} else {

// Next sibling is a reference. Move on.

continue;

}

}

if ( duplicatesFound > 0 ) {

const duplicateExample =

'Duplicated references are highlighted like this.';

mw.notify(

$.parseHTML(

'Found ' + duplicatesFound + ' duplicate reference pairs in the same paragraph. '

+ duplicateExample

),

{ title: 'DuplicatedRefs' }

);

} else {

mw.notify(

$.parseHTML(

'Congratulations! No duplicate reference pairs within the same paragraph found.'

),

{ title: 'DuplicatedRefs' }

);

}

} );

} );