User:SMcCandlish/TidyRefs.js

// TidyRefs should generally not be run on its own, on an article, // without making a more substantive change in the same edit // per the human-editor part of WP:COSMETICBOT (unless fixing actual errors).

if (autosummary === null) var autosummary = true; //generate a short summary if (showdiff === null) var showdiff = true; //show diff after pressing button if (markminor === null) var markminor = false; //mark as minor

function tidyRefs(orientation) { var txt = document.editform.wpTextbox1; // Steps we need to do regardless of horizontal or vertical layout: // Repair outright broken ` `; var preStep3 = preStep2.replace(regexBrokeRefEnd, replaceBrokeRefEnd);

// nothing yet if(orientation == "horizontal") {

// Do quotation and internal spacing cleanup on `` constructions:

var regexName = /|\s*"\s*>|\s+(?:group|follow|extends)\s*=).)*?)\s*"|'\s*([^'"](?:(?!\s*\/>|\s*'>|\s+(?:group|follow|extends)\s*=).)*?)\s*'|((?:[^">\/\s*])(?:(?!\s*\/>|\s*>|\s+(?:group|follow|extends)\s*=).)*))(?:\s+((?:group|follow|extends)\s*=\s*(?:"[^"](?:(?!\s*\/>|\s*"\s*>).)*?\s*"|(?:'[^'"](?:(?!\s*\/>|\s*'\s*>).)*?\s*')|(?:[^>\/\s*]|\s*(?!\/?>)|\/(?!>)))*))*\s*(?:(\/)>|>\s*)/gmi;

// Because JS does not support the advanced conditional-replace `${#:...}` syntax // of ``, we have to jump through some hoops and // deal with the ` />` spacing in a separate operation later. var replaceName = ``; var vStep1 = preStep3.replace(regexName, replaceName);

// Do quotation and internal spacing cleanup on `` constructions:

var regexGroup = /|\s*"\s*>|\s+(?:name|follow|extends)\s*=).)*?)\s*"|'\s*([^'"](?:(?!\s*\/>|\s*'>|\s+(?:name|follow|extends)\s*=).)*?)\s*'|((?:[^">\/\s*])(?:(?!\s*\/>|\s*>|\s+(?:name|follow|extends)\s*=).)*))(?:\s+((?:name|follow|extends)\s*=\s*(?:"[^"](?:(?!\s*\/>|\s*"\s*>).)*?\s*"|(?:'[^'"](?:(?!\s*\/>|\s*'\s*>).)*?\s*')|(?:[^>\/\s*]|\s*(?!\/?>)|\/(?!>)))*))*\s*(?:(\/)>|>\s*)/gmi;

var replaceGroup = ``; var vStep2 = vStep1.replace(regexGroup, replaceGroup);

// Do quotation and internal spacing cleanup on `` constructions:

var regexFollow = /|\s*"\s*>|\s+(?:group|name|extends)\s*=).)*?)\s*"|'\s*([^'"](?:(?!\s*\/>|\s*'>|\s+(?:group|name|extends)\s*=).)*?)\s*'|((?:[^">\/\s*])(?:(?!\s*\/>|\s*>|\s+(?:group|name|extends)\s*=).)*))(?:\s+((?:group|name|extends)\s*=\s*(?:"[^"](?:(?!\s*\/>|\s*"\s*>).)*?\s*"|(?:'[^'"](?:(?!\s*\/>|\s*'\s*>).)*?\s*')|(?:[^>\/\s*]|\s*(?!\/?>)|\/(?!>)))*))*\s*(?:(\/)>|>\s*)/gmi;

var replaceFollow = ``; var vStep3 = vStep2.replace(regexFollow, replaceFollow);

// Do quotation and internal spacing cleanup on `` constructions:

var regexExtends = /|\s*"\s*>|\s+(?:group|follow|name)\s*=).)*?)\s*"|'\s*([^'"](?:(?!\s*\/>|\s*'>|\s+(?:group|follow|name)\s*=).)*?)\s*'|((?:[^">\/\s*])(?:(?!\s*\/>|\s*>|\s+(?:group|follow|name)\s*=).)*))(?:\s+((?:group|follow|name)\s*=\s*(?:"[^"](?:(?!\s*\/>|\s*"\s*>).)*?\s*"|(?:'[^'"](?:(?!\s*\/>|\s*'\s*>).)*?\s*')|(?:[^>\/\s*]|\s*(?!\/?>)|\/(?!>)))*))*\s*(?:(\/)>|>\s*)/gmi;

var replaceExtends = ``; var vStep4 = vStep3.replace(regexExtends, replaceExtends);

// Fix spacing; there's a more "elegant" way to do this stuff, by		// breaking all the regex parts above into proper JS variables and // using those, then doing some string tests to decide when the first // attribute is followed by another and replace any whitespace before // the second with a single space; but it's much easier to just nuke // the whitespace above and re-insert a space here, since these strings // are likely to not have false-positives. var regexSpaceCleanup = /"(name|group|follow|extends)=/g;		var replaceSpaceCleanup = `" $1=`;

var vStep5 = vStep4.replace(regexSpaceCleanup, replaceSpaceCleanup);

// Now to fix invalid nested double-quotes:

// Regex to capture attribute values after ` |">|" (?:name|group|follow|extends)).)*)"/g;

// Function to replace invalid nested double-quotes with single-quotes var replaceInvalidQuotes = function (match, attributeName, attributeValue) { var sanitizedValue = attributeValue.replace(/"/g, "'"); // Replace double-quotes with single-quotes			return '|" (?:name|group|follow|extends)).)*)" (name|group|follow|extends)="((?:(?!" ?\/>|">|" (?:name|group|follow|extends)).)*)"/g;

// Function to replace invalid nested double-quotes with single-quotes var replaceInvalidQuotes2 = function (match, attributeName1, attributeValue1, attributeName2, attributeValue2) { var sanitizedValue2 = attributeValue2.replace(/"/g, "'");			return '|" (?:name|group|follow|extends)).)*)" (name|group|follow|extends)="((?:(?!" ?\/>|">|" (?:name|group|follow|extends)).)*)" (name|group|follow|extends)="((?:(?!" ?\/>|">|" (?:name|group|follow|extends)).)*)"/g;

// Function to replace invalid nested double-quotes with single-quotes var replaceInvalidQuotes3 = function (match, attributeName1, attributeValue1, attributeName2, attributeValue2, attributeName3, attributeValue3) { var sanitizedValue3 = attributeValue3.replace(/"/g, "'");			return '|" (?:name|group|follow|extends)).)*)" (name|group|follow|extends)="((?:(?!" ?\/>|">|" (?:name|group|follow|extends)).)*)" (name|group|follow|extends)="((?:(?!" ?\/>|">|" (?:name|group|follow|extends)).)*)" (name|group|follow|extends)="((?:(?!" ?\/>|">|" (?:name|group|follow|extends)).)*)"/g;

// Function to replace invalid nested double-quotes with single-quotes var replaceInvalidQuotes4 = function (match, attributeName1, attributeValue1, attributeName2, attributeValue2, attributeName3, attributeValue3, attributeName4, attributeValue4) { var sanitizedValue4 = attributeValue4.replace(/"/g, "'");			return '<ref ' + attributeName1 + '="' + attributeValue1 + '" ' + attributeName2 + '="' + attributeValue2 + '" ' + attributeName3 + '="' + attributeValue3 + '" ' + attributeName4 + '="' + sanitizedValue4 + '"';		};

// Apply the replacement function to each match var vStep9 = vStep8.replace(regexRefValues4, replaceInvalidQuotes4);

// Remove leading space in front of ` ` var regexSpaceSlashRef = /\s+<\/ref>/gmi; var replaceSpaceSlashRef = ` `; var vStep10 = vStep9.replace(regexSpaceSlashRef, replaceSpaceSlashRef);

// Paste it back into the page: txt.value = vStep10; }   else if (orientation == "vertical") { //nothing yet }

//Things to do after either vertical or horizontal formatting: // Enforce a space before the closing `/>` characters (but not `>` alone). // We've already normalized to `"/>' so now we change it to `" />`. var regexSlashTagEnd = /(")(\/>)/g;	var replaceSlashTagEnd = `$1 $2`;	var postStep1 = txt.value.replace(regexSlashTagEnd, replaceSlashTagEnd);	// Bonus cleanup: fix ` `, ` `, broken ` `, etc. to ` `	// (this does not handle rare instances of `<br attribute="value" ... />`):

var regexBRmess = /<\s*\/?\s*br\s*\/?\s*>/gi;

var replaceBRmess = ` `;

var postStep2 = postStep1.replace(regexBRmess, replaceBRmess);

// Bonus cleanup: fix ` `, ` `, broken ` `, etc. to ` ` // (this does not handle rare instances of `<hr attribute="value" ... />`):

var regexHRmess = /<\s*\/?\s*hr\s*\/?\s*>/gi;

var replaceHRmess = ` `;

var postStep3 = postStep2.replace(regexHRmess, replaceHRmess);

// Paste it back into the page: txt.value = postStep3; if(autosummary) edit_summary; if(showdiff) 	diff; if(markminor)  document.editform.wpMinoredit.checked = true;

}

function edit_summary { var sum = document.editform.wpSummary; var summary = ";"; summary += " tidyRefs"; if (sum.value.indexOf(summary) == -1) { if (sum.value.match(/[^\*\/\s][^\/\s]?\s*$/)) { sum.value += ""; }   			sum.value += summary; }	}

function diff { document.editform.wpDiff.click; }

$(function {    if(document.forms.editform) {        mw.util.addPortletLink('p-tb', 'javascript:tidyRefs("horizontal")', '\<Tidy\>', 'ca-formatrefs', 'Format refs: tidy quotation marks and whitespace'); //        mw.util.addPortletLink('p-tb', 'javascript:tidyRefs("vertical")', '\<Tidy\> (vertically - FORTHCOMING)', 'ca-formatrefs-vertical', 'Format refs: vertically, tidy quotation marks and whitespace');    } }); /*