User:Jackmcbarn/findargdups.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | Documentation for this user script can be added at User:Jackmcbarn/findargdups. |
jQuery(document).ready(function($) {
var myContent = document.getElementsByName('wpTextbox1')[0];
// -------------------------------------------------------------------------------- //
var mysummary = "Clean up [[:Category:Pages using duplicate arguments in template calls|duplicate template arguments]] using [[:en:User:Frietjes/findargdups|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;}
// -------------------------------------------------------------------------------- //
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 id="FindArgDupsResultsBox"></div>' + div.innerHTML;
}
}
div1 = document.getElementById('FindArgDupsResultsBox');
if( div1 ) {
text = text.replace(/</g, '<');
text = text.replace(/>/g, '>');
div1.innerHTML = div1.innerHTML + '<div class="FindArgDupsResultsBox" ' +
'id="FindArgDupsResultsBox-' + num + '" ' +
'style="max-height:5em; overflow:auto; padding:5px; border:#aaa 1px solid; ' +
'background-color:cornsilk;">' + text + '</div>' + "\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(/(<ref[^<>=]*name[ ]*)=/gi, '$1=');
mytxt = mytxt.replace(/(<ref[^<>=]*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[^<>]*>(?:<[^\/]|[^<])*<\/nowiki[^<>]*>/gi, '');
mytxt = mytxt.replace(/<pre[^<>]*>(?:<[^\/]|[^<])*<\/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) ) {
// 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(/<ref[^<>\/]*>(?:<[^\/]|[^<])*=/gi) >= 0)
&& (j < 50) ) {
tlist[i] = tlist[i].replace(/(<ref[^<>\/]*>(?:<[^\/]|[^<])*)=/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(showresultsbox > 0) { wpClearResultsBox(); }
}
}
// -------------------------------------------------------------------------------- //
});