User:Sarangbot/GadgetToCOA.js

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
/**
@Desc: Quick helper script to replace the [[template: Information]] with the [[template: COAInformation]].
@Revision: 20:27, 11 August 2018 (UTC)
@Author: [[User:Perhelion]] 2018-08 (based on [[MediaWiki:Catcheck.js]] by [[User:Lupo]] / [[MediaWiki:InformationToArtwork.js]] by [[User:Multichill]])
@License: Quadruple licensed GFDL, GPL, LGPL and CC-BY-3.0
Choose whichever license of these you like best :-)
*/
// [[Category:User scripts|InformationToCOA]] <nowiki>
/* global  mw, $*/
/* eslint space-in-parens:0, indent:0, vars-on-top:0, computed-property-spacing:0, array-bracket-spacing:0, quote-props:0, one-var:0, curly:0 */
/* jshint curly:false, scripturl:true, forin:false*/
(function () {
'use strict';

if (mw.config.get('wgNamespaceNumber') !== 6 || mw.config.get('wgAction') !== 'edit') return;

var run = mw.libs.InformationToCOA = function () 
{	// Grab the text
	var textbox = document.getElementById('wpTextbox1'),
		text,
		summary,
		desc,
		blazonOf = '',
		blazon = '',
		ref = '',
		imgen = '',
		ov = '',
		lang = '',
		pos = 0,
		lastIndex = 0,
		match = null,
		// Terms from Template:I18n/COA
		i18nCOA = 
		[	'Escut d\'armes', // ca
			'Znak', // cs
			'Våben', // da
			'(?:Stadt|Gemeinde)wappen|Wappen', // de
			'[Cc]oats? [Oo]f [Aa]rms|[Cc][Oo][Aa]|[Aa]rms', // en
			'Escudo de armas|[Ee]scudo', // es
			'Armoiries|Blason', // fr
			'Blazono', // eo
			'Vapp', // et
			'Armarria', // eu
			'Vaakuna', // fi
			'Escudo', // gl
			'סמל', // he
			'wopon', // hsb
			'Címer', // hu
			'Skjaldarmerki', // is
			'Emblema|Stemma', // it
			'Ģerbonis', // lv
			'Грб', // mk
			'Wapen', // nds
			'Wapen', // nl
			'Våpen', // nn
			'Våpen', // no
			'Herb', // pl
			'Brasão de armas|[Bb]ras[ãa]o', // pt
			'Герб', // ru
			'Erb', // sk
			'Grb', // sl
			'Vapen' // sv
		].join('|'),
		reCOAclean = new RegExp('(' + i18nCOA + ')', 'g'),
		reTmpEnd = /\}\}\n/,
		reDesc = /\s*\|\s*[Dd]escription\s*=\s*(.+\.?)(?:: |\n)/,
		reLang = /^\s*\{\{(\w\w)\s*\| ?(?:1 ?= ?(?!\n))?([^\n]{4})/mg, // without linebreak
		reLang2 = /^\s*\{\{(\w\w)\s*\| ?(?:1 ?=)?\s*/mg,
		reBlason = /:?\s*(?:(?:'')?[„"“»«]|[Bb]lason(?:ierung|ing)?)[\s:]*(?:(?:'')?[„"“»«])?([^\n"“”»«]+)["“”»«]?('')?\s*/g;

	// No text?
	if (!textbox || !textbox.value) return;

	/**
	 *  @brief Fill blazon;
	 *
	 *  @param {string} str search target
	 *  returns cleaned var blazonOf, desc
	 */
	function getBlason(str) 
	{	var match = '', singleBlason;
		blazon = [];
		reBlason.lastIndex = 0;
		while (reBlason.test(str)) 
		{	singleBlason = RegExp.$1;
			match = RegExp.lastMatch.replace(/\s*$/, '');
			match = new RegExp(mw.RegExp.escape(match), 'g');
			// Language tag
			if (reLang2.test(str) && lang !== RegExp.$1) 
			{	lang = RegExp.$1;
				// w:Quotation_mark#Summary_table
				switch (lang) {
				case 'is':
				case 'lf':
				case 'lt':
				case 'sq':
					singleBlason = '„' + singleBlason + '“';
					break;
				case 'bs':
				case 'cs':
				case 'da':
				case 'de':
				case 'hr':
				case 'hu':
					singleBlason = '»' + singleBlason + '«';
					break;
				case 'af':
				case 'cy':
				case 'en':
				case 'ga':
				case 'ia':
				case 'lo':
				case 'th':
				case 'vi':
					singleBlason = '“' + singleBlason + '”';
					break;
				case 'fr':
					singleBlason = '« ' + singleBlason + ' »';
					break;
				default:
					singleBlason = '«' + singleBlason + '»';
				}
				singleBlason = '{{' + lang + '|' + singleBlason + '}}';
			} else	// Only one "block" for each lang
			{	singleBlason = ''; // blazon.pop();
				continue;
			}
			desc = desc.replace(match, '\n');
			blazonOf = blazonOf.replace(match, '\n');
			if (singleBlason) blazon.push(singleBlason);
		}
		reLang2.lastIndex = 0;
		blazon = blazon.join('\n');
	}

	/**
	 *  @brief Find the index position of the next parameter
	 *         and select until the previous.
	 *  @param {number} pos first index
	 *  @param {number} p length of previous match
	 *  @return {string} full text between pos and next parameter
	 */
	function findNextPos(pos, p) 
	{	lastIndex = pos + p;
		p = text.slice(lastIndex).search(/^\s*\|/m);
		lastIndex += p;
		return text.slice(pos, lastIndex);
	}

	function syncCurlyBrackets(block) 
	// Synchronize open & closing curly brackets
	{	for (var reOtag = /\{\{/g, c = 0, reCtag = /\}\}/g; reOtag.test(block); c++)
			if (!reCtag.test(block)) 
			{	// Missing closing tag
				block = block.replace(/\n*$/, '}}');
				if (reLang.test(block)) 
				{	// Then the opening lang-tag is missing on desc.
					lang = RegExp.$1;
					if (!reLang.test(desc))
						desc = '{{' + lang + '|' + desc.replace(/^\s*/, '');
				}
				break;
			}
		lang = '';
		reLang.lastIndex = 0;
		return block;
	}

	text = textbox.value;
	// Don't modify existing!?
	if (/\{\{COAInformation/.test(text))
		return;

	// Get blazonOf including langTag
	if ((match = reDesc.exec(text)))
	{	pos = match.index;
		var blazonOfcont,
			validDesc = false,
			langTag = '',
			p = match[0].length;
		blazonOf = match[1];

		// Get full description
		desc = findNextPos(pos, p);

		/* Get blason first */
		if (reBlason.test(desc))
			getBlason(desc);
		else if (reBlason.test(blazonOf))
			getBlason(blazonOf);

		validDesc = desc.indexOf(blazonOf) !== -1;
		// Remove reDesc (match[1]) from "description"
		desc = desc.replace(reDesc, '\n');
		if (blazonOf)
			// No short desc??
			if (validDesc && lang && !reLang2.test(desc)) 
			{	desc = '{{' + lang + '|' + desc.replace(/^\s*/, '');
				blazonOf = '';
			} else blazonOf = syncCurlyBrackets(blazonOf);

		blazonOfcont = '\n' + blazonOf;
		desc = $.trim(desc);
		/* Get blasonOf second */
		if (desc) 
		{	// If in language tags, copy this
			var part;
			while ((part = reLang.exec(desc)) && part[1] !== lang) 
			{	lang = part[1]; // RegExp.$1;
				langTag = '{{' + lang + '|';
				blazonOf = desc.slice(reLang.lastIndex - 4);
				match = '';
				var firstIndex = part.index; // reLang.lastIndex - part; // common 0
				part = part[0].length - 1; // RegExp.lastMatch.length;
				if ((match = blazonOf.search(reTmpEnd)) !== -1)
					reLang.lastIndex = Math.max(firstIndex, 0);
				else if ((match = blazonOf.search(/\n/)) === -1)
					match = blazonOf.length - 2; // - part // full match

				blazonOf = blazonOf.slice(0, match);

				match += firstIndex;
				// Remove
				desc = desc.slice(0, firstIndex) + desc.slice(part + match);

				if (desc.replace(reTmpEnd, '').replace(reLang2, '').replace(/^\s*/, '')) 
				{	if (!reLang2.test(desc))
						desc = langTag + desc.replace(/^\s*/, '');
				} else { desc = ''; }
				// Add
				blazonOfcont += '\n' + langTag + blazonOf + '}}';
				blazonOf = '';
			}
			blazonOf = $.trim(blazonOf || blazonOfcont) + '\n';
		}

		// Cleanup empty parameter
		if (!blazonOf.replace(reTmpEnd, '').replace(reLang2, '').replace(/\s+/, ''))
			blazonOf = '';
		text = text.slice(0, pos) + text.slice(lastIndex);
	}
	// FIXME: this is only dirty cleanup
	blazonOf = blazonOf.replace(reCOAclean, '')
		.replace (/\| ?1 ?= */, '| ');				// 1st

	if (desc)
		text = text.slice(0, pos) + '\n |description    = ' + desc + '\n' + text.slice(pos);

	if (/[Rr]ef(?:eren(?:ce|z))?[\s:]+([^\n]+)/.test(text)) 
	{	ref = RegExp.$1;
		text = text.replace(RegExp.lastMatch, '');
	}

	if (/\s*\|\s*[Ss]ource\s*=\s*([^\n]+)/.test(text)) 
	{	text = text.replace(RegExp.lastMatch, '\n |source         = ' + RegExp.$1);
	}

	if (/\s*\|\s*[Oo]ther[ _]fields\s*=\s*(\{\{[Ii]m?gen[^\n]+)\s*/.test(text)) 
	{	imgen = RegExp.$1;
		match = RegExp.lastMatch;
		if (/\{\{[Ii](?:gen|mage generation) ?\| ?([Ii](?:nkscape)?|[Aa](?:dobe)?|IA)? ?\|(?:(\d*)\| ?)?(\+\| ?)?s=c\}\}/.test(imgen))
			imgen = RegExp.$1 + '/' + (RegExp.$2 || '0');
		imgen = '\n |image          = ' + imgen + '\n';
		text = text.replace(match, imgen);				// problems when additional fields, e..g 
	}			//		|other fields  = {{Igen|...}}  and  {{InFi|.....}}		(splitting needed)

	if ((match = /\s*\|\s*[Oo]ther[ _]versions\s*= *(.*)/.exec(text))) 
	{	pos = match.index;
		lastIndex = match[0].length;
		if (match[1]) 
		{	ov = match[0].indexOf(match[1], 15);
			ov = findNextPos(pos + ov, lastIndex);
		} else { lastIndex += pos; }
		ov = '\n |versions       = ' + ov;
		text = text.slice(0, pos) + ov + text.slice(lastIndex);
	}

	// Do the actual replace
	text = text
		.replace(/\{\{\s*[Ii]nformation\s*\n?/, '{{COAInformation' +
			'\n |blazon of      =\n' + blazonOf +
			'\n |blazon         = ' + blazon +
			'\n |references     = ' + ref +
			'\n |tincture       = \n ')
		.replace(/\n *\|\s*[Aa]uthor\s*= */,			// exclude Citebook !
			'\n |artist         = ' /* +	artist*/)
		.replace(/\n *\|\s*[Dd]ate\s*= */,				// exclude Citebook !
			'\n |date           = ' /* +	date*/)
		.replace(/\s*\|\s*[Pp]ermission\s*= */,
			'\n |permission     = ')
		.replace(/\s*\|\s*[Oo]ther[ _]fields\s*= */,
			'\n |fields         = ')	// shorten
		.replace(/\n \|permission\s*= *\n/,
			'\n')						// remove empty
		.replace(/\n \|fields\s*= *\n/,
			'\n')						// remove empty
		.replace(/\n \|versions\s*= *\n/,
			'\n');						// remove empty

	// Need jQuery for CodeMirror hook
	$(textbox).val(text);
	// textbox.value = text;
	// Set edit summary
	summary = document.getElementById('wpSummary');
	if (!summary) return;

	summary.value += ((summary.value || '') ? ' ' : '') + 'toCOA-[[MediaWiki:InformationToCOA.js|script]]';

	// Are we sure we want to convert and autosave the page?
	// if (window.confirm('Are you sure you want to convert the template Information to template COAInformation?'))
	//		document.editform.wpSave.click();
};

mw.loader.using('mediawiki.util', run);
}());
// </nowiki>