Note: After saving, changes may not occur immediately. Click here to learn how to bypass your browser's cache.
  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Cmd-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (Cmd-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Clear the cache in Tools → Preferences

For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/* global $, mw, pathoschild */

/**
 * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
 * @see https://meta.wikimedia.org/wiki/TemplateScript
 * @update-token [[File:pathoschild/templatescript.js]]
 */
// <nowiki>
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
	// main namespace
	pathoschild.TemplateScript.add(
		[
			{ name:'Advance header', script: advanceHeader },
			{ name:'Convert pages',  script: converttopages }
		],
		{ forNamespaces: 0 }
	);

	// page namespace
	pathoschild.TemplateScript.add(
		[
			{ name:'Clean up',         script:cleanup },
			{ name:'Clean up&lines',   script:cleanup_and_lines },
			{ name:'Leading {{nop}}',  script:leading_nop },
			{ name:'Pline right',      script:pline_r },
			{ name:'Block center mid', script:blockcentermid },
			{
				name:'Strip gaps',
				script:function strip_gaps(editor) {
					editor
						.replace(/{{ *[Gg]ap *}}/g,  "")
						.options({ minor: true })
						.setEditSummary('Remove gaps used for paragraph indents, this is better done as a global style.');
				}
			},
			{ name:'Sidenotes',             script:sidenotes },
			{ name:'Format header',         script:format_header },
			//{ name:'Metadata',              script:add_metadata },
			{ name:'{{rh}}',                script:RunningHeader },
			//{ name:'Rh (lookup)',           script:set_running_header },
			{ name:'Scriptstyle',           script:scriptstyle },
			{ name:'Derelative',            script:derelative },
			{ name:'Single returns',        script:singleReturns },
			{ name:'<center> to small',     script:smallcenter },
			{ name:'Convert to blk-c mid',  script:blockcenterconvert },
			{ name:'Colons',                script:colons },
			{ name:'Poem',                  script:poem },
			{ name:'Clear page',            script:clearpage },
			{ name:'Pipe links',            script:pipelinks }
		],
		{ forNamespaces: 'page' }
	);

	//editing in any ns:
	pathoschild.TemplateScript.add(
		[
			{ name:'<center> to {{c|',    script:convertcenters },
			{ name:'Quotes',              script:quotes },
			{ name:'Convert redirect',    script:convert_redirect },
			{ name:'Convert ſ to {{ls}}', script:convert_long_s }
		]
	);
});

function pline_r(editor) {
	editor.replace(/([0-9]+) *\n/g,  "{{pline|$1|r}}\n");
}

function convertcenters(editor) {
	editor.replace(/<center>([^<]*)<\/center>/g,  "{{center|$1}}\n");
}

function smallcenter(editor) {
	editor.replace(/<center>([^<]*)<\/center>\n/g, '{{c|{{smaller|$1}}}}');
}

function sidenotes(editor) {
	editor.forField('#wpHeaderTextbox').append('\n{{sidenotes begin}}');
	editor.forField('#wpFooterTextbox').prepend('{{sidenotes end}}\n');
}

function leading_nop(editor) {
	editor.prepend('{{nop}}\n\n');
}

function format_header(editor) {
	editor
		.replace(/{{ *[Hh]eader2/,      "{{header")
		.replace(/( *\| *title *= *)/,      " | title      = ")
		.replace(/( *\| *author *= *)/,     " | author     = ")
		.replace(/( *\| *translator *= *)/, " | translator = ")
		.replace(/( *\| *section *= *)/,    " | section    = ")
		.replace(/( *\| *previous *= *)/,   " | previous   = ")
		.replace(/( *\| *next *= *)/,       " | next       = ")
		.replace(/( *\| *year *= *)/,       " | year       = ")
		.replace(/( *\| *notes *= *)/,      " | notes      = ")
		.replace(/( *\| *portal *= *)/,     " | portal     = ")
		.replace(/( *\| *wikipedia *= *)/,  " | wikipedia  = ")
		.replace(/( *\| *commonscat *= *)/, " | commonscat = ");
}

function convert_long_s(editor) {
	editor.replace(/ſ/g, '{{ls}}');
}

function scriptstyle(editor) {
	editor.replace(/<math\>(.*)<\/math\>/g, '\<math\>\\scriptstyle\{$1\}\<\/math\>');
}

function colons(editor) {
	editor.replace(/::/g, '');
}

function poem(editor) {
	var text = editor.get();
	editor.set('<poem>' + text + '</poem>');
}

function derelative(editor) {
	editor.replace(/\[\[\/(.*)\/\]\]/g, '\[\[$1\|$1\]\]');
}

function singleReturns(editor) {
	editor
		// remove single line breaks; preserve multiple.
		.replace(/([^>\n])\n([^<\n])/g, '$1 $2') //linux
		.replace(/([^>\r\n])\r\n([^<\r\n])/g, '$1 $2'); //windows
}

function quotes(editor) {
	editor
		.replace(/[\u201C\u201D]/g, '\x22') //double smart quotes
		.replace(/[\u2018\u2019\x60]/g, '\x27') //curly single quotes and backticks
		.replace(/&quot;/g, '\x22'); //curly single quotes and backticks
}

function blockcenterconvert(editor) {
	editor.replace(/{{([Ffloat|[Bb]lock) center\|([\s\S]*)}}/g, '$2'); //remove block centres in the main block
	blockcentermid(editor); //add split BC in the header/footer
}

function blockcentermid(editor) {
	editor.forField('#wpHeaderTextbox').append('\n{{block center/s}}');
	editor.forField('#wpFooterTextbox').prepend('{{block center/e}}\n');
}

function cleanup(editor) {
	quotes(editor);
	
	editor
		// remove trailing whitespace at the end of each line
		.replace(/ \n/g, '\n')
		
		// remove trailing whitespace at the end of input
		.replace(/\s+$/g, '')
		
		// convert double-hyphen to mdash
		.replace(/([^\!])--([^>])/g, '$1—$2')
		
		// remove spacing around mdash, but only if it has spaces on both sides
		// (we don't want to remove the trailing space from "...as follows:— "
		.replace(/ +— +/g, '—')
		
		// join words that are hyphenated across a line break
		.replace(/['-]\n/g, '')
		
		// " word -> "word, only if preceded by a space.
		.replace(/ \x22 /g, ' \x22')
		
		
		// remove unwanted spaces around punctuation marks
		.replace(/ ([;:\?!,])/g, '$1')
		
		// : — to :—
		.replace(/: +—/g, ':—')
		
		
		//OCR fixes
		// convert i9 to 19, etc.
		.replace(/[il]([0-9])/g, '1$1')
		
		// "the", "them", "their", "that", "than" etcetera
		.replace(/t[fl]i(a|e)/g, 'th$1')
		
		// "liere", "liave"
		.replace(/(\s)li(ave|ere)(\s)/g, '$1h$2$3')
		
		// wli -> wh
		.replace(/(\s)wli/g, '$1wh')
		.replace(/(\s)whicli/g, '$1which')
		
		// "aud" to "and"
		.replace(/(\s)aud(\s)/g, '$1and$2')
		
		// "v/" to "w"
		.replace(/v\//g, 'w')
		
		// "ét" to "ct" (ligature causes this)
		.replace(/ét/g, 'ct')
		
		// "^V", "AV", "\\" to "W"
		.replace(/\^V/g, 'W')
		.replace(/\AV[a-z]/g, 'W')
		.replace(/\\\\/g, 'W')
		
		.replace(/\[Il]\^/g, 'L')
		
		// remove "�"
		.replace(/�/g, '')
		
		// "U" -> "ll" when preceded by a lowercase letter.
		.replace(/([a-z])U/g, '$1ll')
		
		// l)e -> be
		.replace(/(\s)l\)e(\s)/g, '$1be$2')
		
		// Jn -> In
		.replace(/(\s)Jn(\s)/g, '$1In$2');
}
		
function cleanup_and_lines(editor) {
	cleanup(editor);
	
	editor
		// remove single line breaks; preserve multiple.
		.replace(/([^>\n])\n([^<\n])/g, '$1 $2') //linux
		.replace(/([^>\r\n])\r\n([^<\r\n])/g, '$1 $2') //windows
		
		// collapse sequences of spaces into a single space
		.replace(/  +/g, ' ');
}

// RunningHeader() - puts {{RunningHeader}} in to headerbox
function RunningHeader(editor) {
	editor.forField('#wpHeaderTextbox').append('\n{{RunningHeader|||}}');
}

function convert_redirect(editor) {
	editor
		.replace(/#REDIRECT\s*(\[\[[^\]]*\]\])/g, '{{substXXXXX:dated soft redirect|$1}}') //prevent subst firing when saving this JS
		.replace('substXXXXX', 'subst')
		.setEditSummary('Replaced hard subpage redirect with soft redirect.')
		.options({ minor: false });
}

function advanceHeader(editor) {
	var text = editor.get();
	
	// get header values
	var m = text.match(/ *\\| *section *= *(.*?)[, ]*((?:by .*)?)\n/);
	var prev = m ? m[1] : '';
	var auth = m ? m[2] : '';
	m = text.match(/ *\\| *next *= *(.*)/);
	var section = (m ? m[1] : '').replace(/\[\[\.\.\/(.*)\/\]\]/,  "$1"); //strip relative link
	var next = '[[..//]]';
	
	//apply header values
	editor
		.replace(/( *\\| *section *= *)(.*)/,  "$1" + section +', '+ auth)
		.replace(/( *\\| *next *= *)(.*)/,   "$1" + next )
		.replace(/( *\\| *previous *= *)(.*)/,  "$1[[../" + prev + "/]]");
	
	//advance the pages tag to the next page
	m = editor.get().match(/<pages *index="[^"]*" *from=([0-9]+) *to=([0-9]+)/);
	if (m)
		editor.replace(/(<pages) *(index="[^"]*") *(from=)[0-9]+ *(to=)([0-9]+)/,  "$1 $2 $3"+(parseInt(m[2])+1) +" $4"+(parseInt(m[2])+1));
}

function pipelinks(editor) {
	editor.replace(/\[\[(.*)\/([^\|]*?)\]\]/g,  "[[$1/$2|$2]]");
}

function converttopages(editor) {
	editor.replace(/{{[Pp]age:([^}]*\.\w+)\/([0-9]+)}}/g,  '<pages index="$1" from=$2 to=$2 />');
}

function clearpage(editor) {
	editor.set('');
	editor.forField('#wpFooterTextbox').set('');
	editor.forField('#wpHeaderTextbox').set('');
    $('.quality0 > input').prop('checked', true); //without text
}
// </nowiki>