Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <syntaxhighlight lang=javascript>
// This script aligns dates, currencies and potentially other formatting e.g. international format
// for many nations per [[WP:MOSNUM]] or {{A$}} template for Australian dollar.
// PLEASE READ THE DOCUMENTATION at [[User:Dl2000/DateFix]] (click on the link above) before using.
 
// Feedback and constructive criticism are welcome
// -- disable - some bugs in the general formatting, and much of this was not related
// -- to date fixing e.g. lowercasing "Career" in headings or removing word "Notable" in hdgs

function Dl2_DebugColourStart(clrcod) {
    var startfont = '<font color="';
    var fontlist = new Array("000000", "00ff00", "ff0000", "0000ff", "888800", "008888", "880088", "777777",
                             "ff8888", "88ff88", "8888ff" );
    if (clrcod >= fontlist.length)
        clrcod = 0;

    startfont += fontlist[clrcod];
    startfont += '">';
    return startfont;
}

function Dl2_DebugColourEnd() {
    return "</font>";
}

function Dl2_formatgeneral(){
// reserved for any future general formatting
}

// Only fix errors which can apply globally through the article
// Does not include fixes that do not apply in some cases e.g. quotation or template

function Dl2_fix_common_errors(intxt) {
        var txt = intxt;
 
// straighten non-standard "curly" quotations
        //txt=txt.replace(/“/g, '"'); // lquote - Unicode 201c
        //txt=txt.replace(/”/g, '"'); // rquote - Unicode 201d

//underscore in linked dates - dmy
	txt=txt.replace(/(\[\[[0-3]?\d)_(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))(\]\])/gi, '$1 $2$3');
//underscore in linked dates - mdy
	txt=txt.replace(/(\[\[)(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))_([0-3]?\d\]\])/gi, '$1$2 $3');
 
//remove leading zero from linked date
	txt=txt.replace(/(\[\[)(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s0(\d)(?:th|st|nd|rd|)(\]\])/gi, '$1$2 $3$4');
	txt=txt.replace(/(\[\[)0(\d)(?:th|st|nd|rd|)\s(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))(\]\])/gi, '$1$2 $3$4');
 
//fix 'bda' template redirect
	txt=txt.replace(/{{bda\|([^}]+)}}/gi, '{{birth date and age|$1}}');
 
//fix 'startdate' template redirect
	txt=txt.replace(/{{startdate\|([^}]+)}}/gi, '{{start date|$1}}');

//zap redundant templates ('date', 'as of', 'English', '#dateformat:') 
	txt=txt.replace(/\{\{date\|([^\}\|]+)(?:[^\}]+)?\}\}/gi, '$1');
	txt=txt.replace(/{{#dateformat:([^\}\|]+)(?:\|dmy|\|mdy)?}}/gi,'$1'); 
 
//Replace Image:
        txt=txt.replace(/\[\[Image:/gi, '[[File:');

        return txt;
}

// capitalise month names
function Dl2_cap_month_names(intxt)
{
        var txt = intxt;

	txt=txt.replace(/(\s)jan(|uary|\.)(\s)/g, '$1Jan$2$3');
	txt=txt.replace(/(\s)feb(|ruary|\.)(\s)/g, '$1Feb$2$3');
	txt=txt.replace(/(\d\s)mar(|ch|\.)(\s)/g, '$1Mar$2$3');
	txt=txt.replace(/(\s)mar(|ch|\.)(\s\d)/g, '$1Mar$2$3');
	txt=txt.replace(/(\s)apr(|il|\.)(\s)/g, '$1Apr$2$3');
	txt=txt.replace(/(\d\s)may(,|\.)(\s)/g, '$1May$2$3');
	txt=txt.replace(/(\s)may(|\.)(\s\d)/g, '$1May$2$3');
	txt=txt.replace(/(\s)jun(|e|\.)(\s)/g, '$1Jun$2$3');
	txt=txt.replace(/(\s)jul(|y|\.)(\s)/g, '$1Jul$2$3');
	txt=txt.replace(/(\s)aug(|ust|\.)(\s)/g, '$1Aug$2$3');
	txt=txt.replace(/(\s)sep(|tember|\.)(\s)/g, '$1Sep$2$3');
	txt=txt.replace(/(\d{1,2}\s)sept(\s)/g, '$1Sep$2');
	txt=txt.replace(/(\s)oct(|ober|\.)(\s)/g, '$1Oct$2$3');
	txt=txt.replace(/(\s)nov(|ember|\.)(\s)/g, '$1Nov$2$3');
	txt=txt.replace(/(\s)dec(|ember|\.)(\s)/g, '$1Dec$2$3');

        return txt; 
}

// Protection mechanism replaced in favour of skipping conversions on sections to be "protected" such as quotations or file names.

function Dl2_code_delink_dates(intext) {
 var txt=intext;

//delink ISO8601 dates
	txt=txt.replace(/\[\[([12]\d{3}-[0-1]\d-[0-3]\d)\]\]/gi, '$1');
	txt=txt.replace(/\[\[([12]\d{3})\]\]-\[\[([0-1]\d-[0-3]\d)\]\]/gi, '$1-$2');
	txt=txt.replace(/([12]\d{3})-\[\[([0-1]\d-[0-3]\d)\]\]/gi, '$1-$2');
	txt=txt.replace(/\[\[([12]\d{3})\]\]-([0-1]\d-[0-3]\d)/gi, '$1-$2');
 
//delink full dates
	txt=txt.replace(/\[\[([1-3]?\d)(?:th|st|nd|rd|)[\s_](?:of[\s_])?(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))(?:\]\] \[\[| )([12]\d{3})\]\]/gi, '$1 $2 $3');  
 
	txt=txt.replace(/\[\[(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|)) (?:the\s)?([1-3]?\d)(?:th|st|nd|rd|)(?:\]\],? \[\[|, )([12]\d{3})\]\]/gi, '$1 $2, $3');  
 
//delink single dm or 'dth the m'
	txt=txt.replace(/(?:the\s)?\[\[([1-3]?\d)(?:th|st|nd|rd|)[\s_](?:of[\s_])?(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\]\]/gi, '$1 $2');  
 
//delink single md or 'm the dth'
	txt=txt.replace(/\[\[(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))[\s_](?:the[\s_])?([1-3]?\d)(?:th|st|nd|rd|)\]\]([^\w\d])/gi, '$1 $2$3');
 
//Month+day_number "[[March 7]]th" -> "March 7"
	txt=txt.replace(/\[\[((?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s[1-3]?\d)\]\](?:th|st|nd|rd)/gi, '$1');
 
//month+day+year piped pseudo-ISO dates
	txt=txt.replace(/\[\[(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))( [0-2]?\d|30|31)\|[0-3]?\d-[0-3]?\d\]\]-(?:\[\[)?([1-2]\d\d\d)(\|\d{2,4})?(?:\]\])?/gi, '$1$2, $3');
	txt=txt.replace(/\[\[([0-3]\d\s(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|)))\|[0-3]?\d-[0-3]?\d\]\]-(?:\[\[)?([1-2]\d{3})(\]\])?/gi, '$1 $2');
 
//month+day piped
	txt=txt.replace(/(?:the\s)?\[\[\d{1,2}(?:th|st|nd|rd|)[\s_](?:of[\s_])?(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\|([^\]]{1,30})\]\]/gi, '$1');
 
 //'[[month day|xxXxx]]Xyyyy ' to 'month day, year'
	txt=txt.replace(/\[\[(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s(\d{1,2})(?:th|st|nd|rd|)\|\d?\d\.\d?\d\]\].(\d{3,4})/gi, '$1 $2, $3'); 
 //'[[day month|xxXxx]]Xyyyy' to 'day month year'
	txt=txt.replace(/\[\[(\d{1,2})(?:th|st|nd|rd|)\s(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\|\d?\d\.\d?\d\]\].(\d{3,4})/gi, '$1 $2 $3'); 
 
// century
	txt=txt.replace(/\[\[((?:first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|eleventh|twelfth|thirteenth|fourteenth|fifteenth|sixteenth|seventeenth|eighteenth|nineteenth|twentieth|twenty(?:\s|-)first)(?:\s|-))(century|centuries)(\sAD|\sBC|\sCE|\sBCE|)\]\]/gi, '$1$2$3');
	txt=txt.replace(/\[\[(?:first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|eleventh|twelfth|thirteenth|fourteenth|fifteenth|sixteenth|seventeenth|eighteenth|nineteenth|twentieth|twenty(?:\s|-)first)[\s-_](?:century|centuries)(?:\sAD|\sBC|\sCE|\sBCE|)\|([^\]]{1,30})\]\]/gi, '$1');
	txt=txt.replace(/\[\[(\d{1,2}(?:st|nd|rd|th)[\s-_])(century|centuries)(\sAD|\sBC|\sCE|\sBCE|)\]\]/gi, '$1$2$3');
	txt=txt.replace(/\[\[\d{1,2}(?:st|nd|rd|th)[\s-_](?:century|centuries)(?:\sAD|\sBC|\sCE|\sBCE|)\|([^\]]{1,30})\]\]/gi, '$1');
 
// months
	txt=txt.replace(/\[\[(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\]\]/gi, '$1');
	txt=txt.replace(/\[\[(?:January|February|March|April|May|June|July|August|September|October|November|December)\|([^\]]{1,30})\]\]/gi, '$1');
 
// decades and years -- disabling for now due to potential inappropriate delinks
	// txt=txt.replace(/\[\[(\d{1,3}0)\'?s\]\]/g, '$1s');
	// txt=txt.replace(/\[\[\d{1,3}0\'?s?\|([^\]]{1,30})\]\]/g, '$1');
	// txt=txt.replace(/\[\[(\d{1,3}0)\'?(s)?\s(AD|BC|CE|BCE)\]\]/gi, '$1$2 $3');
	// txt=txt.replace(/\[\[(\d{1,4}[\s_]?)(AD|BC|CE|BCE|)\]\]/gi, '$1$2');
	// txt=txt.replace(/\[\[(AD|BC|CE|BCE|)([\s_]?)(\d{1,4})\]\]/gi, '$3$2$1');
	// txt=txt.replace(/\[\[\d{1,3}0\'?s?\s(?:AD|BC|CE|BCE)\|([^\]]{1,30})\]\]/gi, '$1');
	// txt=txt.replace(/\[\[\d{1,3}0\'?s?\s\(decade\)\|([^\]]{1,30})\]\]/gi, '$1');
	// txt=txt.replace(/\[\[([MDCLXVI]{3,10})\]\]/g, '$1'); -- disabled - would delink things like [[DVD]]
 
//month+year
//Identify surprise or 'Easter egg' diversions linking month+years to year articles. Turn them into month+year links to be dealt with below
	txt=txt.replace(/\[\[\d{1,4}#[^\|\]]+\|((?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s\d{3,4})\]\]/gi, '$1');
	txt=txt.replace(/\[\[((?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s\d{3,4})\]\]/gi, '$1');
	txt=txt.replace(/\[\[(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s\d{3,4}\|([^\]]{1,30})\]\]/gi, '$1');
 
//removed piped years when in full date
	txt=txt.replace(/(\[\[\d{1,2}\s(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\]\],?\s?\[\[)[^\|\]]{1,32}\|(\d{1,4}\]\])/gi, '$1$2');
	txt=txt.replace(/(\[\[(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s\d{1,2}\]\],?\s?\[\[)[^\|\]]{1,32}\|(\d{1,4}\]\])/gi, '$1$2');
 
//Identify surprise or 'Easter egg' diversions linking months to year articles.
	txt=txt.replace(/\[\[\d{1,4}#[^\|\]]+\|(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\]\]/gi, '$1');
 
// month and day piped
	txt=txt.replace(/(\d{4,4}-)\[\[(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))[\s_]\d{1,2}(?:th|st|nd|rd|)\|(\d-)(\d)\]\]/gi, '$10$20$3');
	txt=txt.replace(/(\d{4,4}-)\[\[(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))[\s_]\d{1,2}(?:th|st|nd|rd|)\|(\d\d-)(\d)\]\]/gi, '$1$20$3');
	txt=txt.replace(/(\d{4,4}-)\[\[(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))[\s_]\d{1,2}(?:th|st|nd|rd|)\|(\d-)(\d\d)\]\]/gi, '$10$2$3');
	txt=txt.replace(/\[\[(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))[\s_]\d{1,2}(?:th|st|nd|rd|)\|([^\]]{1,30})\]\]/gi, '$1');
	txt=txt.replace(/\[\[\d{1,2}(?:th|st|nd|rd|)[\s_](?:of[\s_])?(?:Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.?|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\|([^\]]{1,30})\]\]/gi, '$1');
	txt=txt.replace(/\[\[(\d{1,2}(?:st|nd|rd|th))\]\]/gi, '$1');
 
// spaces and commas - mdy birth and death date ranges
	txt=txt.replace(/([^\d][^\w\d])(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s([0-2]?\d|30|31),? (\d{1,3}|[12]?\d{3})(?:[ ]*[-–][ ]*)(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s([0-2]?\d|30|31),? (\d{1,3}|[12]?\d{3})([^\d][^\w\d])/gi, '$1$2 $3, $4 – $5 $6, $7$8');
//dmy birth and death date ranges)
	txt=txt.replace(/([^\d][^\w\d])([0-2]?\d|30|31)\s(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|)),? (\d{1,3}|[12]?\d{3})(?:\s?[-–]\s?)([0-2]?\d|30|31)\s(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|)),? (\d{1,3}|[12]?\d{3})([^\d][^\w\d])/gi, '$1$2 $3 $4 – $5 $6 $7$8');

    return txt;
}
 
function Dl2_delink_ISO_to_dmy() {
    var txt = document.editform.wpTextbox1;
 
// disable in-citation temporarily
//    txt.value = yyyymmdd_to_dmy(txt.value);  // adapted from User:Plastikspork/datetools.js

	txt.value=txt.value.replace(/([^\d\w\/\-%,])([12]\d{3}-\d\d-\d\d)(<\s?\/ref.*?>)/g, '$1$2 $3');

//code to convert ref ISO-dates in citation templates for certain cases

// -([1-3]\d)([^
// -0(\d)([^

// replace date=<ISO8601> within refs
	txt.value=txt.value.replace(/(<\s?ref.*?>[^<]+)(\|\s?date\s?=)([12]\d{3})-(0[0-9]|1[012])-([0-3]\d)([^\d\w\/\-%,])([^<]*?<\s?\/ref.*?>)/gm, 
            function(zz, start1, start2, yyyy, mm, dd, end1, end2)
            {
                return (start1 + start2 + dd + ' ' + Dl2_Monthname(mm) + ' ' + yyyy + end1 + end2);
            } );

    // txt.value = Dl2_remove_leading_zeros_from_nonlinked_dates (txt.value);
 
}
 
//protect certain dates 
//	txt.value=txt.value.replace(/(\[\[4)(AD)/gi, '$1♫$2');
//	txt.value=txt.value.replace(/(March )((?:8|14) Alliance)/gi, '$1♫$2');
//	txt.value=txt.value.replace(/(movement 2) (June)/gi, '$1♫$2');
//	txt.value=txt.value.replace(/(6th\sof\s)(October City)/gi, '$1♫$2');
//	txt.value=txt.value.replace(/(19th\sof\s)(April movement)/gi, '$1♫$2');
//	txt.value=txt.value.replace(/(\[\[May\s1968)(\]\])/gi, '$1 in France|May 1968$2');
//	txt.value=txt.value.replace(/(\[\[June )(1, 1974\]\])/gi, '$1♫$2'); //June 1, 1974 is the name of an album
//	txt.value=txt.value.replace(/(\'\'June )(1, 1974\'\')/gi, '$1♫$2'); 
//	txt.value=txt.value.replace(/(\[\[)((?:2300|2000)\s?AD\]\])/gi, '$1:$2');
 
function Dl2_remove_leading_zeros_from_nonlinked_dates (intext) {

 var txt=intext;
//remove leading zero from nonlinked date
	txt=txt.replace(/([^\d][^\w\d])(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s0(\d)(?:th|st|nd|rd|),?\s([12]\d{3})([^\w\d][^\d]|\b)/gi, '$1$2 $3, $4$5');
	txt=txt.replace(/([^\d][^\w\d])0(\d)(?:th|st|nd|rd|)\s(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s([12]\d{3})([^\w\d][^\d]|\b)/gi, '$1$2 $3 $4$5');
 
	txt=txt.replace(/([^\d][^\w\d])(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))\s0(\d)(?:th|st|nd|rd|)([^\w\d][^\d]|\b)/gi, '$1$2 $3$4');
	txt=txt.replace(/([^\d][^\w\d])0(\d)(?:th|st|nd|rd|)\s(Jan(?:uary|\.|)|Feb(?:ruary|\.|)|Mar(?:ch|\.|)|Apr(?:il|\.|)|May\.?|Jun(?:e|\.|)|Jul(?:y|\.|)|Aug(?:ust|\.|)|Sep(?:tember|\.|t\.|)|Oct(?:ober|\.|)|Nov(?:ember|\.|)|Dec(?:ember|\.|))([^\w\d][^\d]|\b)/gi, '$1$2 $3$4');
 
	return txt;
}

// Tag only
function Dl2_Monthname(monthcode) {
    var myMonths = new Array("0", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

    return myMonths[parseInt(monthcode, 10)]; // the , 10 avoids the jscript cootie where "08" is translated to "0"
}

function Dl2_Monthcode(monthname) {
    var myMonths = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"];

    var mthcode = myMonths.indexOf(monthname.toLowerCase()) + 1;

    return mthcode;
}

function Dl2_CurrMY() {
// current month-year
    var currentDate = new Date();
    var currmonth = currentDate.getMonth();
    var curryear  = currentDate.getFullYear();
    var myMonths = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
    var curryyyymm = myMonths[currmonth] + ' ' + curryear;

    return curryyyymm;
}

function Dl2_IntlTag1() {
    var txt=document.editform.wpTextbox1;
    Dl2_IntlTag(txt);
}

function Dl2_IntlTag(txta){
// leave an existing tag alone
    var rxpd1 = new RegExp("{{Use dmy dates(\\|[^}]*)?}}", "gi");
    var ddfound = txta.value.search(rxpd1);
    if (ddfound >= 0)
    {
        return;
    }

// current month-year
    var curryyyymm = Dl2_CurrMY();

// insert or update 'dmy' template
    txta.value=txta.value.replace(/{{(use (dmy|mdy) dates|dmy|mdy)(\|[^}]*)?}}/gi, '{{Use dmy dates|date='+curryyyymm+'}}');

    var rxpdd = new RegExp("{{Use dmy dates\\|date="+curryyyymm+"}}", "gi");
    var dflagfound = txta.value.search(rxpdd);
    if (dflagfound == -1)
    {
        txta.value='{{Use dmy dates|date='+curryyyymm+'}}\r\n'+txta.value;
    }
}
 
function Dl2_BDA() {
  var txt=document.editform.wpTextbox1;

  var case1handled = 0;

  // case 1: birth_date = dd MMM yyyy
	txt.value=txt.value.replace(/(birth_date[\s]*=[\s]*)([0-3]?[0-9])[\s]*([a-zA-Z]+)[\s]*([1-2][0-9][0-9][0-9])([\s]*\(age.*\))?/gi,
            function(zz, start1, dd, mmm, yyyy, end1)
            {
                var newbda;
                var andage = '';
                if (parseInt(yyyy) > 1920)
                {
                    andage = ' and age';
                }
                newbda =  (start1 + '{{birth date' + andage + '|' + yyyy + '|' + Dl2_Monthcode(mmm) + '|' + dd + '|df=y}}' );
                case1handled = 1;
                return newbda;
            } );

  // case 2: existing {{birth date| - but only if not handled in case 1, and then only for sensible years
  if (case1handled == 0)
  {
    txt.value=txt.value.replace(/{{birth date\|(19[3-9][0-9])\|/gi, '{{birth date and age|$1|');
  }

  var txtsumm=document.editform.wpSummary;
  var summary = "bda";
  if (txtsumm.value.indexOf(summary) == -1) {
    if (txtsumm.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {
      txtsumm.value += " | ";
    }
    txtsumm.value += summary;
  }
  document.forms.editform.wpMinoredit.checked = true;

  document.editform.wpDiff.click();
}

function Dl2_Fdate() {
  var txt=document.editform.wpTextbox1;

  var case1handled = 0;

  // case 1: released = dd MMM yyyy
	txt.value=txt.value.replace(/(released[\s]*=[\s]*)([0-3]?[0-9])[\s]*([a-zA-Z]+)[\s]*([1-2][0-9][0-9][0-9])([\s]*)?/gi,
            function(zz, start1, dd, mmm, yyyy, end1)
            {
                var newrel;
                newrel =  (start1 + '{{film date|' + yyyy + '|' + Dl2_Monthcode(mmm) + '|' + dd + '|df=y}}' );
                case1handled = 1;
                return newrel;
            } );

  var txtsumm=document.editform.wpSummary;
  var summary = "film date";
  if (txtsumm.value.indexOf(summary) == -1) {
    if (txtsumm.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {
      txtsumm.value += " | ";
    }
    txtsumm.value += summary;
  }
  document.forms.editform.wpMinoredit.checked = true;

  document.editform.wpDiff.click();
}


// Section types:
// 0: normal article text
// 1: [[..]] e.g. image, link, category
// 2: {{..}} e.g. template
// 3: <!--..--> comment
// 4: <blockquote>
// 5: <gallery>
// 6: <timeline>
// 7: ".." e.g. nondirectional double quotation
//
// (single quotations not handled - sometimes these can be used for abbrevation e.g. '76)

function Dl2_process_text_section(sectext, sectype) {

    var newtext;

    switch (sectype)
    {
    case 0:
        newtext = Dl2_process_text_section_normal(sectext)
        break;

    case 1:
        newtext = Dl2_process_text_section_link(sectext)
        break;

    case 2:
        newtext = Dl2_process_text_section_template(sectext)
        break;

    // comment, quotation, gallery, timeline - always keep intact
    default:
        newtext = sectext;
        break;
    }

    return newtext;
}

function Dl2_process_text_section_normal(intext) {
    var txt = intext;

    // Fix common normal text non-date items
    txt = Dl2_cap_month_names(txt);

    // lc and tidy any "- present" range
    txt=txt.replace(/(\d)(?:-|–|&ndash;)P(resent)/g, '$1 – p$2');

    //Fix curly-directional double-quotes which are discouraged at [[WP:PUNCT]] - these often get mismatched with straight d-quotes anyway
    txt=txt.replace(/“/g, '"'); // lquote - Unicode 201c
    txt=txt.replace(/”/g, '"'); // rquote - Unicode 201d

    // common regex elements
    var matchmonth = "(Jan(?:uary|\\.|)|Feb(?:ruary|\\.|)|Mar(?:ch|\\.|)|Apr(?:il|\\.|)|May\\.?|Jun(?:e|\\.|)|Jul(?:y|\\.|)|Aug(?:ust|\\.|)|Sep(?:tember|\\.|t\\.|)|Oct(?:ober|\\.|)|Nov(?:ember|\\.|)|Dec(?:ember|\\.|))";
    var matchday = "([0-2]?\\d|30|31)";
    var matchdwd = "([^\\d][^\\w\\d])";
    var matchwdb = "([^\\w\\d][^\\d]|\\b)";
    var nmatchord = "(?:<sup>|<small>)?(?:th|st|nd|rd|)(?:</sup>|</small>)?"; // strip ordinals (and any superscripts) out with a non-match
    var nmatchthe = "(?:the\\s?)?"; // strip spurious "the" prefixing
    var nmatchconj = "(?:and|[-–&]|to|or)"; // strip spurious conjunctions

    if (txt.search(matchmonth) >= 0)
    {
// dmy cleanups...

//rem redundant spaces (and commas) in date formats (moved from fix common errors, to avoid refactoring file names)
        var rx = new RegExp("([^\\d][^\\w\\d]\[?\\[?[0-3]?\\d)[ ]+" + matchmonth + "(\\]\\])?[ ]*,[ ]*(\\[?\\[?\\d{3,4}(\\sAD|\\sBC|\\sCE|\\sBCE|)\\]?\\]?[^\\w\\d][^\\d])", 'gi');
	txt=txt.replace(rx, '$1 $2$3 $4');

        rx = new RegExp("([^\\d][^\\w\\d]\\[?\\[?)" + matchmonth + "[ ]+" + matchday + "(\\]?\\]?)(?:[ ]*,[ ]*)(\\[?\\[?\\d{3,4}(\\sAD|\\sBC|\\sCE|\\sBCE|)\\]?\\]?[^\\w\\d][^\\d])", 'gi');
	txt=txt.replace(rx, '$1$2 $3$4, $5');

        rx = new RegExp("([^\\d][^\\w\\d]\\[?\\[?)" + matchmonth + "[ ]+" + matchday + "(\\]?\\]?)[ ]+(\\[?\\[?\\d{3,4}(\\sAD|\\sBC|\\sCE|\\sBCE|)\\]?\\]?[^\\w\\d][^\\d])", 'gi');
	txt=txt.replace(rx, '$1$2 $3$4, $5'); 

        // comma/of cleanup
        rx = new RegExp(matchmonth + "(?:, | of )(\d{3,4}[\w\d])", 'gi'); //repeat after delinking
        txt=txt.replace(rx, '$1 $2');

//remove unlinked ordinal date formats
        // dth, dth&dth m -> d, d&dm
        rx = new RegExp(nmatchthe + matchday + nmatchord + ", " + matchday + nmatchord + "(\\s?" + nmatchconj + "\\s?)" + matchday + nmatchord + "(?:\\sof\\s?)?\\s" + matchmonth + "([^\\w\\d])", 'g');
        txt=txt.replace(rx,  '$1, $2$3 $4$5 $6');

        // dth&dth m -> d&dm
        rx = new RegExp(nmatchthe + matchday + nmatchord + "(\\s?" + nmatchconj + "\\s?)" + matchday + nmatchord + "(?:\\sof\\s?)?\\s" + matchmonth + "([^\\w\\d])", 'g');
	txt=txt.replace(rx, '$1$2$3 $4$5');

        rx = new RegExp(nmatchthe + matchday + nmatchord + "(?:\\sof\\s?)?\\s" + matchmonth + "([^\\w\\d])", 'g');
        txt=txt.replace(rx, '$1 $2$3');

        rx = new RegExp(matchmonth + "\\s" + nmatchthe + matchday + nmatchord + ",\\s" + nmatchthe + matchday + nmatchord + "(\\s?" + nmatchconj + "\\s?)" + nmatchthe + matchday + nmatchord + "([^\\]\\|\\w\\d][^\\d])", 'g');
        txt=txt.replace(rx, '$1 $2, $3$4 $5$6');

        rx = new RegExp(matchmonth + "\\s" + nmatchthe + matchday + nmatchord + "(\\s?" + nmatchconj + "\\s?)" + nmatchthe + matchday + nmatchord + "([^\\]\\|\\w\\d][^\\d])", 'g');
	txt=txt.replace(rx, '$1 $2$3$4$5');

        rx = new RegExp(matchmonth + "\\s" + nmatchthe + matchday + nmatchord + "([^\\]\\|\\w\\d][^\\d])", 'g');
        txt=txt.replace(rx, '$1 $2$3');

// mdy conversions...

// A. convert mdy-mdy to dmy-dmy (birth and death date ranges)
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + ", ([12]?\\d{0,3})(?:\\s?[-–]\\s?)" + matchmonth + "\\s" + matchday + ", ([12]?\\d{0,3})" + matchdwd, 'g');
	txt=txt.replace(rx, '$1$3 $2 $4 – $6 $5 $7$8');

// B1. m{d}*,y to {d}my
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + "((?:,\\s[0-3]?\\d" + nmatchord + "){0,6}),?(\\s?" + nmatchconj + "\\s+?)" + matchday + nmatchord + ",?\\s(?:of\\s)?(\\d{3,4}[^\\w\\d][^\\d])", 'g');
	txt=txt.replace(rx, '$1$3$4$5$6 $2 $7');

// B2. md-mdy to dm-dmy
        rx = new RegExp(matchdwd + matchmonth + "\\s+" + matchday + nmatchord + "\\s*" + nmatchconj + "\\s*" + matchmonth + "\\s+" + matchday + nmatchord + ",?\\s(?:of\\s)?(\\d{3,4}[^\\w\\d][^\\d])", 'g');
	txt=txt.replace(rx, '$1$3 $2 – $5 $4 $6');

// C. md-md to dm-dm (mdy-mdy or md-mdy cases being caught above)
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + "(?:\\s?[-–]\\s?)" + matchmonth + "\\s" + matchday + matchdwd, 'g');
	txt=txt.replace(rx, '$1$3 $2 – $5 $4$6');

// D. md,d,d -> d,d,dm
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + "((?:,\\s[0-3]?\\d" + nmatchord + "){0,6}), " + matchday + nmatchord + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3$4, $5 $2$6');

// E. convert md,d,d, date ranges to d,d,dm  (multiple, separated by commas)
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + "((?:,?\\s[0-3]?\\d" + nmatchord + "){0,6}),?(\\/|\\s?[-–]\\s?|\\s" + nmatchconj + "\\s+?)" + matchday + nmatchord + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3$4$5$6 $2$7');

// F. md&d -> d&dm
        rx = new RegExp(matchdwd + matchmonth + "((?:\\s[1-3]?\\d" + nmatchord + ",?){1,6})(\\s" + nmatchconj + "\\s+?)" + matchday + nmatchord + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3$4$5 $2$6');

// G. md,d -> d,dm
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + "((?:,?\\s[1-3]?\\d" + nmatchord + "){1,6})" + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3$4 $2$5');

// H. convert md-d date ranges to d-dm  (simple, separated by hyphens and dashes  or 'to')
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + "(\\s?[-–]\\s?|\\sto\\s)" + matchday + nmatchord + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3 $4$5 $2$6');

// I. 'md, md,' to 'dm, dm,'
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + ",\\s?" + matchmonth + "\\s" + matchday + "([,\\.\\s])" + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3 $2, $5 $4$6$7');

// J. convert simple mdy dates to dmy
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + ",?\\s(\\d{1,4}\\s?(?:AD|BC|CE|BCE)[^\\w\\d][^\\d])", 'g');
	txt=txt.replace(rx, '$1$3_$2_$4');

        // test - previous word checks will miss basic cases
        //rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + ",?\\s([12]\\d{3})" + matchwdb, 'g');
	//txt=txt.replace(rx, '$1 $3 $2 $4$5');

// K. md,y -> dmy - ending with \D or end of string
        rx = new RegExp("\\b" + matchmonth + "\\s" + matchday + nmatchord + ",?\\s([12]\\d{3})(\\D|$)", 'g');
	txt=txt.replace(rx, '$2 $1 $3$4');

// L. md -> dm
        // 11De2011 - also allow starting pipe to cover table entry case
        rx = new RegExp("([^\\d][^\\w\\d]|\\|\\s*)" + matchmonth + "\\s" + matchday + nmatchord + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3 $2$4');

// M. Repeat line to capture some instances that get missed first time 
// (needed because the date component 'September 19, 1881' within the string 'March 4-September 19, 1881' is blocked from conversion by the '4')
        rx = new RegExp(matchdwd + matchmonth + "\\s" + matchday + nmatchord + ",?\\s(\\d{1,4})" + matchwdb, 'g');
	txt=txt.replace(rx, '$1$3 $2 $4$5');

// ordinal strip-outs
// N. dth m y -> dmy
        rx = new RegExp(matchdwd + matchday + nmatchord + "\\s" + matchmonth + "\\s(\\d{1,4})" + matchwdb, 'g');
	txt=txt.replace(rx, '$1$2 $3 $4$5');

// O. dth m -> dm
        rx = new RegExp(matchdwd + matchday + nmatchord + "\\s" + matchmonth + matchwdb, 'g');
	txt=txt.replace(rx, '$1$2 $3$4');

// P. dth-dth m -> d-dm
        rx = new RegExp(matchdwd + matchday + nmatchord + "(\\s?[-–]\\s?)" + matchday + nmatchord + "\\s" + matchmonth + matchwdb, 'g');
	txt=txt.replace(rx, '$1$2$3$4 $5$6');
    }
 
    txt = Dl2_remove_leading_zeros_from_nonlinked_dates (txt);

//cleanup any residual commas in International date format
    rx = new RegExp(matchday + nmatchord + "\\s" + matchmonth + ",\\s?(\\d{3,4})([^\\w\\d])", 'g');
    txt=txt.replace(rx, '$1 $2 $3$4');

    return txt;
}

function Dl2_process_text_section_link(intext) {

        var txt = intext;

        // process any date texts within a File: (except in the filename itself)
	txt=txt.replace(/(File:[^\|\]]+)(\|[^\]]*)(\]\])/gi,
            function(zz, start1, body1, end1)
            {
                var newfile = start1 + Dl2_process_text_section_normal(body1) + end1;
                return newfile;
            } );

        // reserved for link processing

        // ??? 9/11 attacks?

        return txt;
}

function Dl2_process_text_section_template(sectext) {
	var txt = sectext;

        var template_key = "";
        var arr_template_key = txt.match(/^(\{\{[\s]*)([^\|\}]*)/);
        if (arr_template_key != null)
        {
            if (arr_template_key.length >= 2)
            {
                template_key = arr_template_key[2];
            }
        }
        template_key = template_key.toLowerCase();
        

//change start and end templates
	txt=txt.replace(/({{(start\sdate|end\sdate)[^|]*\|)df=ye?s?\|([^}]*df=ye?s?)/gi, '$1$2');
 
//change deprecated birth and death templates, start/end and wayback templates
	txt=txt.replace(/({{(?:Birth|Death|release|film date|start date|end date|wayback)[^}]*)\|mf=ye?s?/gi, '$1');
	txt=txt.replace(/({{(?:Birth|Death|release|film date|start date|end date|wayback)[^|]*\|)/gi, '$1df=yes|');
	txt=txt.replace(/({{(?:Birth|Death|release|film date|start date|end date|wayback)[^|]*\|)df=ye?s?\|([^}]*df[ ]?=[ ]?ye?s?)/gi, '$1$2');
 
// dts - format=dmy in this case
        // per {{dts}} doc, remove the obsolete link=off param
	txt=txt.replace(/({{dts[^}]*)(\|link=off)/gi, '$1');
        // clean up existing format...
	txt=txt.replace(/({{dts[^}]*)(\|format=(dmy|mdy))/gi, '$1');
        // then ensure format=dmy is applied if year is first (bugfix courtesy Ohconfucius)
        // txt=txt.replace(/({{dts[^|]*\|)/gi, '$1format=dmy|'); - false pos when date not yr first
        txt=txt.replace(/(\{\{dts[^|]*\|)(?=\d{4}[-\|])/gi, '$1format=dmy|');

// do not attempt to refactor dates for certain parameters, or within certain templates
        var arrSkipParamKeys = new Array("title", "journal", "quote", "source",
             "image", "image_name", "image_file", "work", "filename", "Ship image", "chapter",
             "photo", "contribution" );

// clean up params except for certain cases where a title or quote should remain intact
        var arrParam = txt.split("|");
        var arrParamLength = arrParam.length;
        if (arrParamLength > 0)
        {
            var newtxt = "";

            var skip_all_param = 0;
            
            // don't refactor cquotes, as contained in non-keyed params
            if ((template_key == "cquote") || (template_key == "bquote") ||
               (template_key == "quote") || (template_key == "quotation") ||
               (template_key == "blockquote") ||
               (template_key == "not a typo") || (template_key == "gallery"))
            {
                skip_all_param = 1; // leave all params intact for these cases
            }
            // don't refactor defaultsorts
            var match_ds = template_key.match("^defaultsort:");
            if (match_ds != null)
            {
                skip_all_param = 1; // leave all params intact for these cases
            }
            
			for (ii = 0; ii < arrParamLength; ii++)
            {
                var newParam = arrParam[ii];
                var param_key = newParam.match("^(?:\\s*)([^=]+)(?:=)");
                var skip_this_param = skip_all_param;
                if ((param_key != null) && (skip_all_param == 0))
                {
                    param_key1 =  param_key[1].replace(/\s*$/, ""); // trim any trailing spaces
                    if (arrSkipParamKeys.indexOf(param_key1) >= 0)
                    {
                    	skip_this_param = 1;
                    }
                }

				if (skip_this_param == 0)
                {
                    newtxt = newtxt + Dl2_process_text_section_normal(newParam);
                }
                else
                {
                    newtxt = newtxt + newParam;
                }
                     
                if (ii < (arrParamLength - 1))
                {
                    newtxt = newtxt + "\|";
                }
            }
            txt=newtxt;
        }

        return txt;
}

// Concept is to avoid "protection" mechanism - instead of string replacements across the entire
// article, parse the article into separate sections according to whether they are templates, quotations,
// images, links, or formattable article text. This may actually be less efficient than global
// substitutions, but will tend to avoid false positives by skipping those portions of an article
// which should not be refactored.

function Dl2_dates_to_dmy(isdebug){

    var txt=document.editform.wpTextbox1;

    Dl2_IntlTag(txt);

    txt.value = Dl2_fix_common_errors(txt.value);

    txt.value = Dl2_code_delink_dates(txt.value);

    // Parse article text into arrSectionText elements, each idenified with arrSectionType
    var arrSectionText = new Array();
    var arrSectionType = new Array();

    // define corresponding start and end markers for sections...
    var arrSectStarts = new Array('', '[[', '{{', '<!--', '<blockquote>',  '<gallery',  '<timeline>',  "\"", '<div', "''" );
    var arrSectEnds   = new Array('', ']]', '}}', '-->',  '</blockquote>', '</gallery>', '</timeline>', "\"", '</div>', "''" );

    var numDigits = "0123456789";

    var currSectionType = 0;
    var currSectionIndex = 0;
    var currSectionError = 0;
    var hasQMismatch = 0;
    var hasUTmismatch = 0;

    var currpos = 0;
    var last_currpos = 0;

    // Initial pass to parse out the text sections...
    // Set up local variables for text content and length to slightly improve efficiency - txt won't change in this first loop

    var txtValue = txt.value;
    var txtValueLength = txt.value.length;

    while (currpos < txtValueLength)
    {
        if (currSectionType == 0)
        {
            // assume normal text - look for the start of another type e.g. [[, {{, "
            var nextSectionType = 0;
            var ixNext = txtValueLength;
            for (ii = 1; ii < arrSectStarts.length; ii++)
            {
                var ixPos = txtValue.indexOf(arrSectStarts[ii], currpos);
                if (ixPos < 0)
                {
                    ixPos = txtValueLength + 1;
                }
                if (ixPos < ixNext)
                {
                    ixNext = ixPos;
                    nextSectionType = ii;
                }
            }

            if (ixNext < txtValueLength)
            {
                // special case for double quote - stay in normal section type if this is not a starting
                // double quote (generally inches designation e.g. 7", as immediately preceded by digit(s))

                if (nextSectionType == 7) // double quotation per arrSectStarts[]
                {
                    var beforequote = txtValue.slice(ixNext - 1, ixNext);
                    if (beforequote)
                    {
                        if (numDigits.indexOf(beforequote) >= 0)
                        {
                            nextSectionType = 0; // start another normal section
                            ixNext++;
                        }
                    }
                }

                if (ixNext > currpos)
                {
                    arrSectionText[currSectionIndex] = txtValue.slice(currpos, ixNext);
                    arrSectionType[currSectionIndex] = 0;
                    currSectionIndex++;
                }
                currSectionType = nextSectionType;
                currpos = ixNext;
            }
            else
            {
                // no more sections found - write out to the end
                arrSectionText[currSectionIndex] = txtValue.slice(currpos);
                arrSectionType[currSectionIndex] = 0;
                currpos = txtValueLength;
            }
        }
        else
        {
            if (currSectionType >= arrSectEnds.length)
            {
                currpos++; // fail-safe trap
                currSectionType = 0;
            }
            else
            {
                var levels_in = 1; // up a level for each {{, down for each }} - outer template ends when level gets to 0
                var ixEnd = currpos + 1;
                var sStarter = arrSectStarts[currSectionType];
                var sTerminator = arrSectEnds[currSectionType];
                var identical_ends = 0;
                if (sStarter == sTerminator)
                {
                    identical_ends = 1;
                }

                while ((levels_in > 0) && (ixEnd < txtValueLength))
                {
                    var chk = txtValue.slice(ixEnd, ixEnd + sTerminator.length);

                    // if starter == terminator, this is only one level, only watch for the terminator!
                    if ((chk == sStarter) && (identical_ends == 0))
                    {
                        levels_in++;
                        ixEnd = ixEnd + sStarter.length;
                    }
                    else
                    {
                        if (chk == sTerminator)
                        {
                            levels_in--;
                            ixEnd = ixEnd + sTerminator.length;
                        }
                        else
                        {
                            var nxtStarter = txtValue.indexOf(sStarter, ixEnd + 1);
                            var nxtTerminator = nxtStarter;
                            if (identical_ends == 0)
                            {
                                nxtTerminator = txtValue.indexOf(sTerminator, ixEnd + 1);
                            }
                            if ((nxtStarter < nxtTerminator) && (nxtStarter >= 0))
                            {
                                ixEnd = nxtStarter;
                            }
                            else
                            {
                                if (identical_ends == 1)
                                {
                                    // in quotation sections, automatically terminate at the end of the para and reset section scan
                                    var nxtPara = txtValue.indexOf("\n", ixEnd + 1);
                                    if (nxtPara < 0)
                                    {
                                        nxtPara = txtValueLength;
                                    }
                                    if (nxtTerminator > nxtPara)
                                    {
                                        // alert("unterminated quote (" + sTerminator + ") at end of para:\n" + txtValue.slice(currpos, nxtPara) + " ixEnd=" + ixEnd);
                                        ixEnd = nxtPara;
                                        levels_in = 0;
                                        currSectionError = nxtPara;
                                    }
                                }

                                if (nxtTerminator < 0)
                                {
                                    ixEnd = txtValueLength;
                                }
                                else
                                {
                                    ixEnd = nxtTerminator;
                                }
                            }
                        }
                    }
                }

                if (levels_in > 0)
                {
                    var err_pos = currpos + 100;
                    if (err_pos > txtValueLength)
                    {
                        err_pos = txtValueLength - 1;
                    }

                    // alert('unterminated section of text! (missing ' + arrSectEnds[currSectionType] +
                    //       ')\nCheck from start of this section:\n' +  txtValue.slice(currpos, err_pos) + '...');

                    hasUTmismatch = hasUTmismatch + 1;
                    arrSectionText[currSectionIndex] = '{{check quotation}}<!-- MISSING ' +
                               arrSectEnds[currSectionType] + ' following: -->' +
                               txtValue.slice(currpos);
                    arrSectionType[currSectionIndex] = currSectionType;
                    currpos = txtValueLength;
                }
                else
                {
                    // write out section
                    var nextSectionText;
                    if (currSectionError > 0)
                    {
                        nextSectionText = txtValue.slice(currpos, currSectionError + 1) +
                                          '{{check quotation}}';
                        if (ixEnd > currSectionError + 2)
                        {
                            nextSectionText = nextSectionText + txtValue.slice(currSectionError + 1, ixEnd);
                        }
                        hasQMismatch++;
                    }
                    else
                    {
                        nextSectionText = txtValue.slice(currpos, ixEnd);
                    }
                    arrSectionText[currSectionIndex] = nextSectionText;
                    arrSectionType[currSectionIndex] = currSectionType;
                    currSectionError = 0;
                    currSectionIndex++;
                    currpos = ixEnd;
                }
                currSectionType = 0;
            }
        }
    }

    // Second pass - now refactor each section of text according to its type
    var newtxt = "";

    for (j = 0; j < arrSectionText.length; j++)
    {
        if (isdebug == 1)
        {
            newtxt += Dl2_DebugColourStart(arrSectionType[j]);
        }
        newtxt += Dl2_process_text_section(arrSectionText[j], arrSectionType[j]);
        if (isdebug == 1)
        {
            newtxt += Dl2_DebugColourEnd();
        }
    }

    txt.value = newtxt;

// ??? to re-do
//change start and end templates
//change deprecated birth and death templates

}
 
function Dl2_MOSNUM_edit_summary(nation){
// Add a tag to the summary box
 var txt=document.editform.wpSummary;
    var summary = "unify formatting per [[WP:MOSNUM|MoS]], script-assisted (" + nation + " subject)";
	if (txt.value.indexOf(summary) == -1) {
		if (txt.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {
			txt.value += ", ";
		}
		txt.value += summary;
	}
//	document.forms.editform.wpMinoredit.checked = true;
	document.editform.wpDiff.click();
}
 
function Dl2_ADollar() {
  var txt=document.editform.wpTextbox1;

  txt.value=txt.value.replace(/{{AUD\|([^}]+)}}/gi, '{{A\$|$1}}');
  txt.value=txt.value.replace(/\[\[Australian\sdollar\|AU\$\]\]/gi, '{{A\$}}');
  txt.value=txt.value.replace(/AU\$/gi, 'A\$');
}

// type - the full word of the English variant type to be tagged to
function Dl2_EngTag(type) {
    var txt=document.editform.wpTextbox1;

    // If there's an existing tag, prompt to override
    langvars = new Array("American", "Australian", "British (Oxford)", "British", "Canadian", "Hong Kong", "Indian", "Irish", "Jamaican", "New Zealand", "Pakistani", "South African" );
    var curryyyymm = Dl2_CurrMY();

    for (i = 0; i < langvars.length; i++)
    {
        var rxTemp = new RegExp('{{[_ ]*(?:[Uu]se[_ ]+' + langvars[i] + '[_ ]+English|[Ee]ngvarB)[_ ]*(?:|\\|[ ]*date[ ]*=[^{}\\|]*)[ ]*}}', 'gi');
        if ((langvars[i] != type) && (txt.value.search(rxTemp) >= 0))
        {
            if (confirm(langvars[i] + ' English tag already exists - override?'))
            {
                var newtag='{{Use ' + type + ' English|date='+curryyyymm+'}}';
                txt.value=txt.value.replace(rxTemp, newtag);
            }
            else
            {
                return;
            }
        }
    }

    // add tag if not already present (or changed above)
    var rxpdd = new RegExp("{{Use " + type + " English", "gi");
    var dflagfound = txt.value.search(rxpdd);
    if (dflagfound == -1)
    {
        txt.value='{{Use ' + type + ' English|date='+curryyyymm+'}}\r\n'+txt.value;
    }
}

function Dl2_nobots_check() {
    var txt=document.editform.wpTextbox1;
    var rxnobot = new RegExp("\{\{bots *\| *deny=all", "i");
 
    // If there's an existing nobots tag, prompt and return 1

    if (txt.value.search(rxnobot) >= 0)
    {
        alert("Article is flagged to deny all bots");
        return 1;
    }
 
    return 0;
}


 
function Dl2_all_dates_to_dmy(nation, isdebug) {
  Dl2_formatgeneral();
  Dl2_dates_to_dmy(isdebug);
  // Dl2_delink_ISO_to_dmy();
  Dl2_MOSNUM_edit_summary(nation);
}

function Dl2_CommonStyleFix(engtag, countrycode, isdebug)
{
  if (Dl2_nobots_check() == 0)
  {
    if (engtag != "")
    {
      Dl2_EngTag(engtag);
    }
    Dl2_all_dates_to_dmy(countrycode, isdebug);
  }
}

function Dl2_Australianate() {
  Dl2_ADollar();
  Dl2_CommonStyleFix("Australian", "AUS", 0);
}

function Dl2_NewZealandate() {
  Dl2_CommonStyleFix("New Zealand", "NZL", 0);
}

function Dl2_UKanate() {
  Dl2_CommonStyleFix("British", "UK", 0);
}

function Dl2_IntlDate() {
  if (Dl2_nobots_check() == 0)
  {
    Dl2_all_dates_to_dmy("international", 0);
  }
}

function Dl2_Debugged_Intl() {
  Dl2_all_dates_to_dmy("international", 1);
}

function Dl2_AusNZate() {
  Dl2_all_dates_to_dmy("AUS/NZL", 0);
}

function Dl2_IEanate() {
  Dl2_CommonStyleFix("Irish", "IRL", 0);
}

function Dl2_HKanate() {
  Dl2_CommonStyleFix("Hong Kong", "HKG", 0);
}

function Dl2_JAManate() {
  Dl2_CommonStyleFix("Jamaican", "JAM", 0);
}

function Dl2_ZAanate() {
  Dl2_CommonStyleFix("South African", "ZAF", 0);
}
 
function Dl2_Indianate() {
  Dl2_CommonStyleFix("Indian", "IND", 0);
}
 
$(function () {
 if(document.forms.editform) {
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_Australianate()', 'Australianate', 'ca-unitfixer', 'Format for Australia', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_NewZealandate()', 'New Zealandate', 'ca-unitfixer', 'Format for New Zealand', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_AusNZate()', 'AUS/NZ', 'ca-unitfixer', 'Format for Australia/New Zealand', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_UKanate()', 'UKanate', 'ca-unitfixer', 'Format for UK', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_IEanate()', 'Irelandate', 'ca-unitfixer', 'Format for Ireland', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_ZAanate()', 'South Africanate', 'ca-unitfixer', 'Format for South Africa', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_Indianate()', 'Indianate', 'ca-unitfixer', 'Format for India', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_JAManate()', 'Jamaicanate', 'ca-unitfixer', 'Format for Jamaica', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_HKanate()', 'HKandate', 'ca-unitfixer', 'Format for Hong Kong', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_IntlDate()', 'International dates', 'ca-unitfixer', 'International date formatting', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_IntlTag1()', 'Intl tag', 'ca-unitfixer', 'International dmy date tag', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_BDA()', 'BDA', 'ca-unitfixer', 'Standardise infobox birth dates', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_Fdate()', 'FDate', 'ca-unitfixer', 'Standardise infobox film date', '', '');
  mw.util.addPortletLink('p-tb', 'javascript:Dl2_Debugged_Intl()', '(Debug Test)', 'ca-unitfixer', 'Debug test', '', '');

  }
});
// </syntaxhighlight>