User:Frietjes/findargdups.js

jQuery(document).ready(function($) {

var myContent = document.getElementsByName('wpTextbox1')[0];

// -------------------------------------------------------------------------------- //

var mysummary = "Clean up duplicate template arguments using findargdups";

if(typeof findargdupseditsummary == 'string') {mysummary = findargdupseditsummary;}

var morefound = "More duplicates found, fix some and run again!";

if(typeof findargdupsmorefound == 'string') {morefound = findargdupsmorefound;}

var linktext = "Find dups";

if(typeof findargdupslinktext == 'string') {linktext = findargdupslinktext;}

var showresultsbox = 0;

if(typeof findargdupsresultsbox == 'string') { showresultsbox = 1;}

var showalertbox = 1;

if(typeof findargdupsnoalertbox == 'string') { showalertbox = 0; showresultsbox = 1;}

var nonefound = 'No duplicates were found!';

if(typeof findargdupsnonefound == 'string') { nonefound = findargdupsnonefound;}

// -------------------------------------------------------------------------------- //

if(mw.config.get('wgNamespaceNumber') != -1 && myContent) {

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

var portletlink = mw.util.addPortletLink('p-tb', '#', linktext, 't-fdup');

$(portletlink).click(function(e) {

e.preventDefault();

wpFindDuplicateArgs(0);

});

});

}

// -------------------------------------------------------------------------------- //

function wpAddResultsBox(text, num)

{

var div = document.getElementById('wpSummaryLabel').parentNode;

if( div ) {

if( num < 2 ) {

if( document.getElementById('FindArgDupsResultsBox') ) {

document.getElementById('FindArgDupsResultsBox').innerHTML = '';

} else {

div.innerHTML = '

' + div.innerHTML;

}

}

div1 = document.getElementById('FindArgDupsResultsBox');

if( div1 ) {

text = text.replace(/

text = text.replace(/>/g, '>');

div1.innerHTML = div1.innerHTML + '

'id="FindArgDupsResultsBox-' + num + '" ' +

'style="max-height:5em; overflow:auto; padding:5px; border:#aaa 1px solid; ' +

'background-color:cornsilk;">' + text + '

' + "\n";

}

}

}

function wpClearResultsBox()

{

var div = document.getElementById('wpSummaryLabel').parentNode;

if( div ) {

if( document.getElementById('FindArgDupsResultsBox') ) {

document.getElementById('FindArgDupsResultsBox').innerHTML = '';

}

}

}

// -------------------------------------------------------------------------------- //

function wpFindDuplicateArgs(debugflag)

{

// Flag used to determine if we have issued an alert popup

var alertissued=0;

// Flag used to determine if we've selected one of the problem templates yet

var selectedone=false;

// Internal for and while loop variables

var i=0; var j=0; var loopcount=0;

// Array used to hold the list of unnested templates

var tlist = [];

// Regular expression which matchs a template arg

var argexp = new RegExp("\\|[\\s]*([^\\s=\\|\\[\\]\\{\\}][^=\\|\\[\\]\\{\\}]*[^\\s=\\|\\[\\]\\{\\}]|[^\\s=\\|\\[\\]\\{\\}]|)[\\s]*=", "gm");

// Copy the contents of the text window so we can modify it without problems

var mytxt = myContent.value;

// Remove some includeonly, noinclude, and onlyinclude tags

mytxt = mytxt.replace(/<\/?[ ]*(?:includeonly|noinclude|onlyinclude)[ ]*>/gi, '');

// Remove PAGENAME, BASEPAGENAME, ... nested inside of triple braces

mytxt = mytxt.replace(/\{\{\{[^\{\}]*\|[ ]*\{\{[A-Z]+\}\}\}\}\}/g, '');

// Mangle some ref tags

mytxt = mytxt.replace(/(=]*name[ ]*)=/gi, '$1=');

mytxt = mytxt.replace(/(=]*group[ ]*)=/gi, '$1=');

// Mangle some math tags

loopcount = 0;

while((mytxt.search(/<[\s]*math[^<>]*>[^<>=]*=/gi) >= 0) && (loopcount < 10)) {

mytxt = mytxt.replace(/(<[\s]*math[^<>]*>[^<>=]*)=/gi, '$1=');

loopcount++;

}

// Remove some triple braces and parserfunctions inside of triple braces

loopcount = 0;

while((mytxt.search(/\{\{\{[^\{\}]*\}\}\}/g) >= 0) && (loopcount < 5) ) {

mytxt = mytxt.replace(/\{\{\{[^\{\}]*\}\}\}/g, '');

mytxt = mytxt.replace(/\{\{#[a-z]+:[^{}=]*\}\}/gi, '');

loopcount++;

}

// Replace some bare braces with HTML equivalent

mytxt = mytxt.replace(/([^\{])\{([^\{])/g, '$1{$2');

mytxt = mytxt.replace(/([^\}])\}([^\}])/g, '$1}$2');

// Remove newlines and tabs which confuse the regexp search

mytxt = mytxt.replace(/[\s]/gm, ' ');

// Compress whitespace

mytxt = mytxt.replace(/[\s][\s]+/gm, ' ');

// Remove some nowiki and pre text

mytxt = mytxt.replace(/]*>(?:<[^\/]|[^<])*<\/nowiki[^<>]*>/gi, '');

mytxt = mytxt.replace(/]*>(?:<[^\/]|[^<])*<\/pre[^<>]*>/gi, '');

// Remove some HTML comments

mytxt = mytxt.replace(//gm, '');

// Modify some = inside of file/image/wikilinks which cause false positives

loopcount = 0;

while((mytxt.search(/\[\[[^\[\]\{\}]*=/gi) >= 0) && (loopcount < 5) ) {

mytxt = mytxt.replace(/(\[\[[^\[\]\{\}]*)=/gi, '$1=');

loopcount++;

}

// Now start unnesting the templates

loopcount = 0;

while( (mytxt.search(/(?:\{\{|\}\})/g) >= 0) && (loopcount < 20) ) {

// Replace some bare braces with HTML equivalent

mytxt = mytxt.replace(/([^\{])\{([^\{])/g, '$1{$2');

mytxt = mytxt.replace(/([^\}])\}([^\}])/g, '$1}$2');

// Split into chunks, isolating the unnested templates

var strlist = mytxt.split(/(\{\{[^\{\}]*\}\})/);

// Loop through the chunks, removing the unnested templates

for (i = 0; i < strlist.length; i++) {

if( strlist[i].search(/^\{\{[^\{\}]*\}\}$/) >= 0 ) {

tlist.push(strlist[i]);

strlist[i] = '';

}

}

// Join the chunks back together for the next iteration

mytxt = strlist.join('');

loopcount++;

}

// Preprocess some = signs inside of non-citation-templated citations

for(i=0; i < tlist.length; ++i) {

j=0;

while( (tlist[i].search(/\/]*>(?:<[^\/]|[^<])*=/gi) >= 0)

&& (j < 50) ) {

tlist[i] = tlist[i].replace(/(\/]*>(?:<[^\/]|[^<])*)=/gi, '$1=');

}

}

// Now find duplicates in the list of unnested templates

for(i=0; i < tlist.length; ++i) {

// Add numbers for unnamed parameters

var unp=0;

tlist[i] = tlist[i].replace(/(\{\{[\s_]*#invoke[\s ]*:[^{}\|]*)\|([^{}\|=]*\|)/gi, '$1|0=$2');

while((tlist[i].search(/(\{\{(?:[^{}\[\]]|\[\^\[\*\]\])*?\|)((?:[^{}\[\]=\|]|\\[\[[^\[\*\]\])*(?:\||\}\}))/) >= 0)

&& (unp < 25)) {

unp++;

tlist[i] = tlist[i].replace(/(\{\{(?:[^{}\[\]]|\[\^\[\*\]\])*?\|)((?:[^{}\[\]=\|]|\\[\[[^\[\*\]\])*(?:\||\}\}))/, '$1' + unp + '=$2');

}

// Array to hold any found duplicate args (reduce number of alerts)

var f = [];

// Split the template into an array of | arg = ... strings

var p = tlist[i].match(argexp);

if( p ) {

for(j=0; j < p.length; ++j) {

p[j] = p[j].replace(argexp, '$1');

}

p = p.sort();

for(j=0; j < p.length - 1; ++j) {

if( p[j] == p[j+1]) {

f.push(p[j]);

}

}

}

if(f.length > 0) {

alertissued = alertissued + 1;

if(alertissued < 5) {

if(!selectedone) {

var selectmatch = myContent.value.match(tlist[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s+/g, '\\s*'));

if(selectmatch !== null) {

myContent.setSelectionRange(selectmatch.index, selectmatch.index + selectmatch[0].length);

selectedone = true;

}

}

if(showresultsbox > 0) {

wpAddResultsBox('Duplicate \"' + f.join('\", \"') + '\" in\n' + tlist[i], alertissued);

}

if(showalertbox > 0) {

alert('\"' + f.join('\", \"') + '\" in\n' + tlist[i]);

}

} else if(alertissued == 6) {

alert(morefound);

}

}

}

if (alertissued) {

var editsummary = document.getElementsByName('wpSummary')[0];

if(typeof editsummary == 'object') {

if (editsummary.value.indexOf(mysummary) == -1) {

if (editsummary.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {

editsummary.value += '; ' + mysummary;

} else {

editsummary.value += mysummary;

}

}

}

if(selectedone) {

setTimeout(function() {myContent.focus();}, 0);

}

} else if(nonefound.trim().length > 0) {

mw.notify(nonefound);

} else {

if(showresultsbox > 0) { wpClearResultsBox(); }

}

}

// -------------------------------------------------------------------------------- //

});