User:Erutuon/scripts/graveToAcuteRedirect.js

Note – after saving, you may have to bypass your browser’s cache to see the changes.

  • Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
  • Konqueror and Chrome: click Reload or press F5;
  • Opera: clear the cache in Tools → Preferences;
  • Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.

/*
 * Automatically create three types of Ancient Greek redirects:
 * - from titles with graves to the corresponding title with an acute:
 *     [[καὶ]] → [[καί]]
 * - from titles with apostrophe-like characters to the straight apostrophe:
 *     [[γ’]] → [[γ']]
 * - from a title with two accents in the final word to the version with the
 *   final accent removed:
 *     [[ἦέ]] → [[ἦε]]
 *
 * Install by adding this to your [[Special:MyPage/common.js]]:

importScript('User:Erutuon/scripts/graveToAcuteRedirect.js');

 */

/* jshint boss: true, undef: true, unused: true */
/* globals $, mw, OO */
// <nowiki>

(function () {
if (mw.config.get('wgCurRevisionId') !== 0)
	return;

const decomposedTitle = mw.config.get('wgPageName').normalize('NFD');
	
// U+02BC MODIFIER LETTER APOSTROPHE, U+1FBD GREEK KORONIS, U+1FBF GREEK PSILI,
// U+2019 RIGHT SINGLE QUOTATION MARK
const wrongApostrophe = /[ʼ᾽᾿’]/g;
// U+0027 APOSTROPHE
const rightApostrophe = "'";
// const curlyApostrophe = "’";

// in mainspace and page hasn't been created and title contains a character in
// the Greek and Coptic block
if (mw.config.get('wgNamespaceNumber') === 0
		&& /[Ͱ-Ͽ]/.test(decomposedTitle)) {
	const grave = '\u0300';
	const acute = '\u0301';
	const circumflex = '\u0342';
	const consonants = 'βγδζθκλμνξπρςστφχψ';
	
	let rightTitle;
	
	if (decomposedTitle.includes(grave)) {
		const finalGraveRegex = new RegExp(grave + '([' + consonants + ']*)$');
		if (!finalGraveRegex.test(decomposedTitle)) {
			mw.notify("No grave accent at end of term!");
			return;
		}
		
		// No need to recompose; the server does that automatically.
		rightTitle = decomposedTitle.replace(finalGraveRegex, acute + '$1');
	} else if (wrongApostrophe.test(decomposedTitle)) {
		rightTitle = decomposedTitle.replace(wrongApostrophe, rightApostrophe);
	} else {
		// If last word has two accents, remove the last and redirect to it.
		const match = decomposedTitle.match(/[^_]+$/);
		const lastWord = match && match[0];
		if (lastWord) {
			const allTones = new RegExp("[" + acute + grave + circumflex + "]", "g");
			const match = lastWord.match(allTones);
			if (match && match.length === 2) {
				let i = 0;
				rightTitle = decomposedTitle.replace(lastWord,
					lastWord.replace(allTones, function (tone) {
						return ++i === 2 ? "" : tone;
					}));
			}
		}
	}
	
	if (rightTitle) {
		const redirect = '#REDIRECT [[' + rightTitle.normalize('NFC') + ']]';
		$(function () {
			switch (mw.config.get('wgAction')) {
				case 'edit': case 'submit':
					const textbox = $('#wpTextbox1');
					if (textbox.textSelection('getContents') === '')
						textbox.textSelection('setContents', redirect);
					break;
				case 'view': {
					mw.loader.using([ 'mediawiki.Uri', 'oojs-ui' ]).done(function () {
						// Use preloadtext parameter implemented in [[MediaWiki:Common.js]]
						// to set text in textbox.
						const button = new OO.ui.ButtonWidget({
							label: 'Create redirect to ' + rightTitle,
							href: new mw.Uri(location.href).extend({ action: 'edit', preloadtext: redirect }).toString()
						});

						const buttonContainer = $('<p>').append(button.$element);

						$('#firstHeading').after(buttonContainer);
					});
				}
			}
		});
	}
}


function hasAmbig(greekStr) {
	// αιυ followed by diacritics (not macron, breve, circumflex, iota subscript)
	greekStr = greekStr.normalize('NFD');
	const diaeresis = '\u0308';
	let match;
	const vowelAndDiacritics = /([αεου]?ι|[αεηο]?υ|α)([\u0300-\u036F]*)/gi;
	while (match = vowelAndDiacritics.exec(greekStr)) {
		const [ , vowels, diacritics ] = match;
		// macron, breve, circumflex (perispomeni), iota subscript
		if (!/[\u0304\u0306\u0342\u0345]/.test(diacritics)
				&& (vowels.length === 1 || diacritics.includes(diaeresis))) {
			return true;
		}
	}
	return false;
}

/*
console.log('start tests');
for (const [ word, expected ] of [
	[ 'ἑκατόμβας', true ],
	[ 'αἰδοίη', false ],
	[ 'ἄγετ', true ],
	[ 'Βηθσαϊδά', true ],
	[ 'Βηθσαῐ̈δ', false ],
]) {
	const result = hasAmbig(word);
	console.log(word, expected, result, result === expected ? 'success' : 'failure');
}
*/

// in mainspace and page hasn't been created and title contains a character in
// the Greek and Coptic block and last character of title is straight apostrophe
if (mw.config.get('wgNamespaceNumber') === 0
		&& /[Ͱ-Ͽ]/.test(decomposedTitle)
		&& decomposedTitle[decomposedTitle.length - 1] == rightApostrophe
		&& mw.config.get('wgAction') === 'edit') {
	
	const charsTemplate = '{{subst:chars|grc|'
		+ decomposedTitle.normalize('NFC')
		+ '}}';
	const ambigParameter = hasAmbig(decomposedTitle)
		? '|' + charsTemplate.replace(rightApostrophe, '')
		: '';
	
	const contents = `==Ancient Greek==

===Pronunciation===
{{grc-IPA${ambigParameter}}}

===POS===
{{grc-POS|${ charsTemplate /* for curly apostrophe */ }}}

# {{apocopic form of|grc|${charsTemplate}}}`;
	
	$('#wpTextbox1').textSelection('setContents', contents);
}

})();

// </nowiki>