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 form-of entries based on meta-data within entries.
 * See [[User:Conrad.Irwin/creation.js/documentation]] for information.
 *
 * Entry creation rules per language are located at [[User:Conrad.Irwin/creationrules.js]].
 */

/*
 * The starting point of the whole script.
 * 
 * This adds a hook to the page load event so that the script runs
 * and processes the accelerated links once the page is done loading.
 */
jQuery.getScript('//en.wiktionary.org/w/index.php?action=raw&title=User:Aryamanarora/creationrules.js&ctype=text/javascript&smaxage=21600&maxage=86400', function () {
		// Don't do anything unless the current page is in the main namespace.
		if (wgNamespaceNumber && wgPageName != 'Wiktionary:Sandbox')
			return;
		
		// Find all the links that are marked as accelerated.
		// Then go over each red link and see if we can "enhance" it into a green link.
		poss = find_form_of_spans ();
		
		for (var i = 0;i<poss.length; i++)
		{
			var link = find_red_link (poss[i]);
			
			if (link)
			{
				// We can enhance this link, let's do it.
				try
				{
					process_link (poss[i].className.replace(/(^| +)form-of( +|$)/,'').split(' '), link);
					link.style.color = '#22CC00';
				}
				catch(e)
				{
					// We didn't manage to process the link; something must be wrong.
					// Show dotted underline under the link instead to indicate this.
					link.style.borderBottom = '2px dashed #22CC00';
					console.log(e.message);
				}
			}
		}

	} );

/*
 * Recursively find anything tagged with the "form-of" class.
 */
function find_form_of_spans ()
{
	if (typeof(document.getElementsByClassName) == 'function')
	{
		return document.getElementsByClassName('form-of');
	}
	else
	{
		var spans = document.getElementsByTagName ('span');
		var form_ofs = new Array ();

		for (var i=0; i<spans.length; i++)
		{
			if (spans[i].className.match(/(^| +)form-of( +|$)/))
			{
				form_ofs.push (spans[i]);
			}
		}

		return form_ofs;
	}
}

/*
 * Recursively find first red link in "form-of" spans.
 * FIXME: would be better to return an array as multiple params often occur
 */
function find_red_link (span)
{
	var poss = span.firstChild;

	while (poss)
	{
		if(poss.nodeType == 1)
		{
			if (poss.nodeName.toUpperCase () == 'A' && poss.className.indexOf('new') >= 0)
				return poss;
			else if (recurse = find_red_link(poss))
				return recurse;
		}
		
		poss = poss.nextSibling;
	}

	return null;
}

/*
 * Convert a raw red link into a snazzy green one.
 */
function process_link (details, link)
{
	// First, gather all the information that was given in the span's class.
	var params = get_params(details, link);
	
	// Now build a new "green link" URL to replace the original red link with
	var workerHref = '';
	
	// First, try to create an entry "internally".
	if (preload = get_preload_text(params))
	{
		workerHref = '&preloadtext=' + encodeURIComponent(preload);
	}
	else
	{
		throw new Error('Unable to process link: "' + details + '"');
	}
	
	// Did we manage to generate a form-of entry?
	// Then replace the link's URL.
	link.href +=
		'&editintro=User:Conrad.Irwin/creation.js/intro' + workerHref
		+ '&summary=' + encodeURIComponent('Creating ' + params.form + ' form of [[' + params.origin_pagename + ']] ([[WT:ACCEL|Accelerated]])' )
		+ '&preloadminor=true';
}

// Get the parameters from the span's class
function get_params(details, link)
{
	// Default values
	var params = {
		lang: null,
		pos: get_part_of_speech(link),
		form: null,
		gender: null,
		transliteration: null,
		origin: wgTitle,
		origin_pagename: wgTitle,
		target: link.innerText || link.textContent,
		target_pagename: link.innerText || link.textContent  // TODO
		};
	
	// Go over each value and add it
	for (var i = 0; i < details.length; i++)
	{
		if (details[i].match(/(^| +)lang-([^ ]+)( +|$)/))
		{
			params.lang = RegExp.$2;
		}
		else if (details[i].match(/(^| +)([^ ]+)-form-of( +|$)/))
		{
			params.form = RegExp.$2;
		}
		else if (details[i].match(/(^| +)gender-(([mfn]+|c)(pl)?)( +|$)/))
		{
			params.gender = RegExp.$2;
		}
		else if (details[i].match(/(^| +)transliteration-(.+)( +|$)/))
		{
			params.transliteration = unAnchorEncode(RegExp.$2);
		}
		else if (details[i].match(/(^| +)origin-(.+)( +|$)/))
		{
			params.origin = unAnchorEncode(RegExp.$2);
		}
	}
	
	return params;
}

// Exception class
function PreloadTextError(message)
{
	this.name = 'PreloadTextError';
	this.message = message;
}

PreloadTextError.prototype = new Error();
PreloadTextError.prototype.constructor = PreloadTextError;

function unAnchorEncode(x)
{
	return decodeURI(x.replace(/\./g, '%').replace(/_/g, '%20'));
}

//The part of speech, normally determined by other means.
function get_part_of_speech (link)
{
	// Acceleration can be added to inflection tables too.
	// This tells the search script to skip headers with these names.
	var skipheaders = ["alternative forms", "antonyms", "conjugation", "declension", "derived terms", "inflection", "mutation", "related terms", "synonyms", "translations", "usage notes"];
	var node = link;
	
	while(node)
	{
		while (node.previousSibling)
		{
			node = node.previousSibling;
			
			if (node.nodeType == 1 && node.nodeName.match(/^[hH][3456]$/))
			{
				var header = $( node ).find( ".mw-headline" ).text().replace(/^[1-9.]* /,'').toLowerCase();
				
				if (skipheaders.indexOf(header) == -1)
					return header;
			}
		}
		
		node = node.parentNode;
	}
	
	throw new Error('This entry seems to be formatted incorrectly. Does it have a language and part-of-speech header?');
}