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.

// Scripts and notes by Hesperian

/**
 * 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() {
	/*********
	** Register scripts
	*********/
	// stuff I routinely do at the start
	pathoschild.TemplateScript.add(
		[
			{ name: 'header', script: header, accessKey: 'z' },
			{ name: 'clean up', script: cleanup, accessKey: 'x' },
			{ name: 'uc', script: uc },
			{ name: 'hwe', script: hwe }
		],
		{ forNamespaces: 'page' } // common fields
	);

	// stuff I can do any time
	pathoschild.TemplateScript.add([
		{ name: 'title', script: title, accessKey: 't' },
		{ name: 'author', script: author, accessKey: 'a' },
		{ name: 'author (surname first)', script: surnameFirst, accessKey: ',' },
		{ name: 'small-caps', script: smallcaps, accessKey: 'c' },
		{ name: 'upper', script: upper, accessKey: '6' }
	]);

	// stuff I do at the end
	pathoschild.TemplateScript.add(
		[
			{ name: 'hws', script: hws },
			{ name: 'makeref', script: makeref },
			{ name: 'makeoverflow1', script: makeoverflow1 },
			{ name: 'makeoverflow2', script: makeoverflow2 },
			{ name: 'footer', script: footer, accessKey: 'f' }
		],
		{ forNamespaces: 'page' } // common fields
	);

	// stuff I only do via shortcuts; if I could create these shortcuts without adding them to the sidebar, I would.
	pathoschild.TemplateScript.add([
		{ name: 'pagename', script: putpagename, accessKey: 'n' }
	]);


	/*********
	** Extract page info
	*********/
	var pagenum = (function() {
		var m = /\.djvu\/([0-9]+)&action=edit/g.exec(location.href);
		if (!m) return null;
		return parseInt(m[1]);
	})();
	var quality = (function getQuality() {
		var q = document.getElementById('pagequality');
		if (!q)
			return "Nonexistent";
		else {
			var c = q.getAttribute("class");
			switch(c) {
			case "quality0": return "Without text";
			case "quality1": return "Not proofread";
			case "quality2": return "Problematic";
			case "quality3": return "Proofread";
			case "quality4": return "Validated";
			}
		}
		return null;
	})();
	var proofed = quality !== 'Nonexistent' && quality !== 'Not proofread';

	var specialFormats = [
		// add as many as you like... 3}}
		// format is ["url_to_match", "verso header", "recto header", "footer if no ref", "footer if ref"]
		[
			"Journalproceedi421908roya",
			"{{running header|left="+(pagenum-34)+"|center={{smaller|J. H. MAIDEN.}}}}",
			"{{running header|center={{smaller|RECORDS OF AUSTRALIAN BOTANISTS.}}|right="+(pagenum-34)+"}}",
			"",
			"{{block center|{{smallrefs}}}}"
		],
        [
			"Emu",
			"{{running header|left="+(pagenum-12)+"|center={{small-caps|author}}, \'\'title\'\'|right=[ Emu 1st July}}",
			"{{running header|left=Vol. IV. 1904 ]|center={{small-caps|author}}, \'\'title\'\'|right="+(pagenum-12)+"}}",
			"",
			""
		],
        [
			"Tender_buttons",
			"",
			"",
			"",
			"{{center|"+(pagenum-6)+"}}"
		],
		[
			"_Folk-Lore_Journal_",
			"{{running header|left="+(pagenum-8)+"|center={{smaller|SZÉKELY FOLK-MEDICINE.}}}}",
			"{{running header|center={{smaller|SZÉKELY FOLK-MEDICINE.}}|right="+(pagenum-8)+"}}",
			"",
			"{{block center|{{smallrefs}}}}"
		],
		[
			"_A_Quarterly_Review",
			"{{running header|left="+(pagenum-12)+"|center=\'\'The Religious Ideas and Practices of\'\'}}",
			"{{running header|center=\'\'The Aborigines of Northern Asia.\'\'|right="+(pagenum-12)+"}}",
			"",
			"{{block center|{{smallrefs}}}}"
		],
		[
			"Magyars",
			"{{running header|left="+(pagenum-76)+"|center={{smaller|NOTES TO THE FOLK-TALES.}}}}",
			"{{running header|center={{smaller|NOTES TO THE FOLK-TALES.right="+(pagenum-76)+"|}}}}",
			"",
			"{{block center|{{smallrefs}}}}"
		],
		[
			"The_fairy_tales_of_Hans_Christian_Andersen",
			"{{larger block|{{running header|left="+(pagenum-22)+"|center=ANDERSEN\'S FAIRY TALES}}}}",
			"{{larger block|{{running header|center=THE GOLOSHES OF HAPPINESS|right="+(pagenum-22)+"}}}}",
			"",
			""
		],
		[
			"_Tegner",
			"{{running header|left="+(pagenum-32)+"|center={{larger|THE EMPEROR'S NEW CLOTHES}}}}\n{{rule}}",
			"{{running header|center={{larger|THE EMPEROR'S NEW CLOTHES}}|right="+(pagenum-32)+"}}\n{{rule}}",
			"",
			""
		],
		[
			"_Craigie",
			"{{running header|left="+(pagenum-12)+"|center=OLE LUK-OIE}}",
			"{{running header|center=OLE LUK-OIE|right="+(pagenum-12)+"}}",
			"",
			""
		],
		[
			"Walker",
			"{{running header|left="+(pagenum-42)+"|center=ANDERSEN'S FAIRY TALES}}",
			"{{running header|center=THE TRAVELLING COMPANIONS|right="+(pagenum-42)+"}}",
			"",
			""
		]
	];


	/*********
	** Define scripts
	*********/
	// === FOR CONVERSIONS ===
	// Convenience function: converts some text into title case
	function titlecase(text) {
		// split text into individual words and examine them one by one
		var textArray = text.toLowerCase().split(" ");
		for (var i in textArray) {
			switch(textArray[i]) {
				case "a":
				case "an":
				case "and":
				case "as":
				case "at":
				case "but":
				case "by":
				case "etcetera":
				case "etc.":
				case "for":
				case "from":
				case "in":
				case "nor":
				case "of":
				case "o'":
				case "on":
				case "or":
				case "the":
				case "to":
				case "with":
				case "versus":
				case "vs.":
				case "v.":
				case "yet":
					break; // don't capitalise articles, "to" as part of an infinitive, prepositions or short conjunctions
				default: // capitalise everything else
					textArray[i] = textArray[i].substring(0,1).toUpperCase() + textArray[i].substring(1,textArray[i].length);
					break;
			}
		}

		// capitalise first word regardless
		textArray[0] = textArray[0].substring(0,1).toUpperCase() + textArray[0].substring(1,textArray[0].length);

		// capitalise last word regardless
		var last = textArray.length-1;
		textArray[last] = textArray[last].substring(0,1).toUpperCase() + textArray[last].substring(1,textArray[last].length);

		// reconstruct title
		var titleCase="";
		for (i in textArray) {
			titleCase += textArray[i];
			if (i < last) titleCase += " ";
		}

		return titleCase;
	}

	// == SIDEBAR TOOLS ==
	function cleanup(editor) {
		var headerbox = editor.forField('#wpHeaderTextbox');
		var footerbox = editor.forField('#wpFooterTextbox');

		// anything noincluded at the start or end of the edit box should be pushed into the header and footer respectively.
		if(editor.get().match(/^<noinclude>/)) {
			var e = editor.get().indexOf("</noinclude>");

			// append to header a trimmed version of whatever is inside the leading noinclude
			headerbox.append('\n' + editor.get().substr(11, e-11).replace(/^\s+|\s+$/g, ''));

			// remove leading noinclude from editbox
			editor.set(editor.get().substr(e+12));
		}

		if (editor.get().match(/<\/noinclude>$/)) {
			var s = editor.get().lastIndexOf("<noinclude>");

			// prepend to footer a trimmed version of whatever is inside the trailing noinclude
			footerbox.prepend(editor.get().substr(s+11, editor.get().length-s-11-12).replace(/^\s+|\s+$/g, '') + '\n');

			// remove trailing noinclude from editbox
			editor.set(editor.get().substr(0, s));
		}

		editor
			// remove trailing spaces at the end of each line
			.replace(/ +\n/g, '\n')

			// remove trailing whitespace preceding a hard line break
			.replace(/ +<br *\/?>/g, '<br />')

			// remove trailing whitespace at the end of page text
			.replace(/\s+$/g, '')

			// remove trailing spaces at the end of refs
			.replace(/ +<\/ref>/g, '</ref>')

			// remove trailing spaces at the end of template calls
			.replace(/ +}}/g, '}}')

			// convert double-hyphen to mdash (avoiding breaking HTML comment syntax)
			.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:— ",
			// bearing in mind that the space will already be gone if at end of line).
			.replace(/ +— +/g, '—')

			// join words that are hyphenated across a line break
			// (but leave "|-" table syntax alone)
			.replace(/([^\|])-\n/g, '$1');

		// stuff to do only if the page doesn't contain a <poem> tag:
		if (editor.get().indexOf("<poem>") === -1) {
			editor
				// remove single line breaks; preserve multiple.
				// but not if there's a tag, template or table syntax either side of the line break
				.replace(/([^>}\|\n])\n([^<{\|\n])/g, '$1 $2')

				// collapse sequences of spaces into a single space
				.replace(/  +/g, ' ');
		}

		editor
			// dump spurious hard breaks at the end of paragraphs
			.replace(/<br *\/?>\n\n/g, '\n\n')

			// remove unwanted spaces around punctuation marks
			.replace(/ ([;:\?!,])/g, '$1')


			// unicodify
			.replace(/&mdash/g, '—')
			.replace(/&ndash/g, '–')
			.replace(/&quot;/g, '"')

			// straighten quotes and apostrophes.
			.replace(/[“”]/g, '"')
			.replace(/[‘’`]/g, '\'')


			//OCR fixes
			// convert i9 to 19, etc.
			.replace(/[il]([0-9])/g, '1$1')

			// "the", "them", "their", etcetera
			.replace(/tlie/g, 'the')

			// "U" -> "ll" when preceded by a lowercase letter.
			.replace(/([a-z])U/g, '$1ll')



			// replace "float center" with "block center"; original template name was misleading enough be warrant routinely fixing
			.replace(/\{\{float center/g, '{{block center')
			.replace(/<center>\s*([.\n]*?)\s*<\/center>/g, '{{center|$1}}');

		// temporary fix just for Portrait
		if (location.href.indexOf('A_Portrait_of_the_Artist_as_a_Young_Man') !== -1)
			editor.replace(/\n\n\n/g, '\n\n');
	}

	// automatically insert running header into header box
	function header(editor) {
		if (pagenum === null)
			return;

		var isEven = pagenum % 2 === 0;

		var headerbox = editor.forField('#wpHeaderTextbox');

		var generic = true;
		for (var f in specialFormats) {
			var format = specialFormats[f];
			if (location.href.indexOf(format[0]) !== -1) {
				if (isEven)
					headerbox.append('\n' + format[1]);
				else
					headerbox.append('\n' + format[2]);

				generic = false;
				break;
			}
		}

		// no special header matched, use a generic running header
		if (generic) {
			if (isEven)
				headerbox.append('\n{{running header|left=|center=}}'); // assume verso, with page number at left
			else
				headerbox.append('\n{{running header|center=|right=}}'); // assume recto, with page number at right
		}

		// if this is unproofed text, then delete the first line of the OCR text, which presumably is raw OCR of the header we've just inserted
		if (!proofed)
			editor.set(editor.get().slice(editor.get().indexOf('\n') + 1));
	}

	// insert formatted references into footer box, if needed.
	function footer(editor) {
		var footerbox = editor.forField('#wpFooterTextbox');
		if (editor.get.indexOf("<ref>") === -1 && editor.get().indexOf("{{#tag:ref") === -1) {
			// page contains no refs
			var generic = true;
			for (var f in specialFormats) {
				var format = specialFormats[f];
				if (location.href.indexOf(format[0]) !== -1) {
					footerbox.replace('<references/>', format[3]);
					generic = false;
					break;
				}
			}

			// no special footer matched, use just strip out the references tag
			if (generic)
				footerbox.replace('<references/>','');
		}
		else {
			var generic = true;
			for (var f in specialFormats) {
				var format = specialFormats[f];
				if (location.href.indexOf(format[0]) !== -1) {
					footerbox.replace('<references/>', format[4]);
					generic = false;
					break;
				}
			}

			// no special footer matched, so use a generic ref tag
			if (generic)
				footerbox.replace('<references/>','{{block center|{{smallrefs}}}}\n');
		}
	}

	//Make selected text into appropriately capitalised title link
	// e.g. "THE MAN FROM SNOWY RIVER" —> "[[The Man from Snowy River|THE MAN FROM SNOWY RIVER]]"
	function title(editor) {
		return editor.replaceSelection(function(text) {
			var target = titlecase(text);
			return target === text
				? '[['+text+']]'
				: '[['+target+'|'+text+']]';
		});
	}

	//Make selected text into author link
	function author(editor) {
		editor.replaceSelection(function(name) {
			// if name is all in capitals, convert target to title case
			var target = name === name.toUpperCase()
				? titlecase(name)
				: name;
			return '[[Author:'+target+'|'+name+']]';
		});
	}

	function surnameFirst(editor) {
		editor.replaceSelection(function(name) {
			// If name is all in capitals, convert target to title case.
			var target = name === name.toUpperCase()
				? titlecase(name)
				: name;

			// split text into individual words
			var nameArray = name.split(" ");

			// put last first, followed by a comma, then all the rest preceded by spaces
			name = nameArray[nameArray.length - 1] + ",";
			for (var i = 0; i < nameArray.length - 1; i++)
				name = name+" "+nameArray[i];

			return '[[Author:'+target+'|'+name+']]';
		});
	}

	//Mark selected text up with small-caps
	function smallcaps(editor) {
		editor.replaceSelection(function(pre) {
			// Applying small-caps to all-caps text is pointless...
			// ... unless the all-caps is OCR of text that is actually small-caps.
			// Check if text is all-caps, and if it is, convert it to title case before applying small-caps.
			if (pre == pre.toUpperCase())
				pre = titlecase(pre);
			return '{{small-caps|'+pre+'}}';
		});
	}

	// As you work your way through the page, when you encounter a reference, just mark it with <ref></ref> tags and continue.
	// Once you've got to the end of the page and proofed the references, simply highlight each reference in turn,
	// and use this function to move it to its proper position.
	function makeref(editor) {
		var editbox = $('#wpTextbox1').get(0);
		var refStart = editbox.selectionStart;
		var refEnd = editbox.selectionEnd;

		var firstref = editbox.value.indexOf('<ref></ref>');
		if (-1 != firstref) {
			editbox.value = editbox.value.slice(0,firstref+5)
				+ editbox.value.slice(refStart, refEnd)
				+ editbox.value.slice(firstref+5, refStart)
				+ editbox.value.slice(refEnd);
		}
	}

	// As you work your way through the page, when you encounter a reference, just mark it with <ref></ref> tags and continue.
	// Once you've got to the end of the page and proofed the references, simply highlight the overflow reference, and use this
	// function to move it to its proper position.
	function makeoverflow1() {
		var editbox = $('#wpTextbox1').get(0);
		var refStart = editbox.selectionStart;
		var refEnd = editbox.selectionEnd;

		var firstref = editbox.value.indexOf('<ref></ref>');
		if (-1 != firstref) {
			editbox.value = editbox.value.slice(0,firstref)
				+ "{{#tag:ref|"
				+ editbox.value.slice(refStart, refEnd)
				+ " <includeonly>{{#section:Page:"
				+ mw.config.get('wgPageName').replace(/_/g, ' ')
				+ "/"
				+ (pagenum+1)
				+ "|overflow}}</includeonly>}}"
				+ editbox.value.slice(firstref+11, refStart)
				+ editbox.value.slice(refEnd);
		}
	}

	function makeoverflow2(editor) {
		var editbox = $('#wpTextbox1').get(0);
		var refStart = editbox.selectionStart;
		var refEnd = editbox.selectionEnd;

		editbox.value = "<section begin=\"text\"/>"
			+ editbox.value.slice(0,refStart)
			+ "<section end=\"text\"/>\n\n<div style=\"font-size:smaller;\">\n<section begin=\"overflow\"/>"
			+ editbox.value.slice(refStart, refEnd)
			+ "<section end=\"overflow\"/>\n</div>";
	}

	//wrap first word in hwe template
	function hwe(editor) {
		var to = editor.get().search(/\W/);
		if (to == -1) to = editor.get().length;

		var pre = editor.get().substring(0, to);

		var post = '{{hyphenated word end|'+pre+'|…'+pre+'}}';
		editor.set(post + editor.get().substring(to));
	}

	//wrap last word in hws template
	function hws(editor) {
		var from = editor.get().lastIndexOf(" ");
		if (from == -1) from = 0;
		else from = from + 1;

		var pre = editor.get().substring(from);
		if (pre.slice(-1) == "-")
			pre = pre.slice(0, -1);

		var post = '{{hyphenated word start|'+pre+'|'+pre+'…}}';
		editor.set(editor.get().substring(0, from) + post);
	}

	function putpagename(editor) {
		var pagename = mw.config.get('wgPageName').replace(/_/g, ' ');
		editor.replaceSelection(pagename);
	}

	function uc(editor) {
		editor.replace(/(\{\{[Uu]c\s*\|\s*)([^\}]+)(\}\})/g, function(match, before, text, after) {
			return before + text.toUpperCase() + after;
		});
	}

	function upper(editor) {
		editor.replaceSelection(function(text) {
			return text.toUpperCase();
		});
	}
});
// </nowiki>

if (mw.toolbar) {
	// <nowiki>
	$('#wpTextbox1').wikiEditor('addToToolbar', {
		section: 'main',
		group: 'format',
		tools: {
			'custom-Lgr': {
				label: 'Lgr ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{larger|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom--Bl': {
				label: '-Bl • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{larger block|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom-Sm': {
				label: 'Sm ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{smaller|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom--Bs': {
				label: '-Bl • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{smaller block|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom-C': {
				label: 'C • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{center|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom-Bl-c': {
				label: 'Bl-c • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{block center|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom-Qt': {
				label: 'Qt • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{block center|{{smaller block|',
						post: '}}}}',
						sampleText: ''
					}
				}
			},
			'custom-Rl': {
				label: 'Rl • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{rule|',
						post: 'em}}',
						sampleText: ''
					}
				}
			},
			'custom-Di': {
				label: 'Di • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{drop initial|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom-Rt': {
				label: 'Rt • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{right|',
						post: '}}',
						sampleText: ''
					}
				}
			},
			'custom-Ref': {
				label: 'Ref • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '<ref>',
						post: '</ref>',
						sampleText: ''
					}
				}
			},
			'custom-Sct-b': {
				label: 'Sct-b • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '<section begin=',
						post: ' />',
						sampleText: ''
					}
				}
			},
			'custom-Sct-e': {
				label: 'Sct-e •',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '<section end=',
						post: ' />',
						sampleText: ''
					}
				}
			},
			'custom-Ttl': {
				label: 'Ttl • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{{center|{{larger block|',
						post: '}}}}',
						sampleText: ''
					}
				}
			},
			'custom-Img-Flt': {
				label: 'Img-Flt • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '{| style="float:right; "\n|-\n|width=280px|[[File:Page FUM of Fairy tales from Hans Christian Andersen (Walker).png|frameless|center|alt=]]\n{{center|{{x-smaller|',
						post: '}}}}\n|}\n',
						sampleText: ''
					}
				}
			},
			'custom-Img-Ctr': {
				label: 'Img-Ctr • ',
				type: 'button',
				icon: '',
				action: {
					type: 'encapsulate',
					options: {
						pre: '[[File:Page FUM of Fairy tales from Hans Christian Andersen (Walker).png|frameless|center|alt=]]\n\n{{center|{{x-smaller block|',
						post: '}}}}',
						sampleText: ''
					}
				}
			}
		}
	});
	//</nowiki>
}