User:Xhienne/creation.js

/* * Automatically create form-of entries based on meta-data within entries. * See User:Conrad.Irwin/creation.js/documentation for information. */

/* * Language-specific formatting rules for form-of entries. * * These come in two different types. The first type is the "internal" type. * These are entries whose content is generated directly from within the script. * The second type is "external", where the content is generated by template-izing one * of the subpages of the script, such as User:Conrad.Irwin/creation.js/basicNoun. * * The internal type is always attempted first. If no internal rule is available for the * current to-be-created entry, the external type is used as a fallback. */

/* * "Internal" entry generation rules. * * These are all called via the get_preload_text function, which returns a fully-formed entry with a language header. */ function get_preload_text(params) {	try {		if (!get_preload_text[params.lang]) return false; var entry = { lang_header: '=={'+'{subst:#invoke:language utilities|lookup_language|' + params.lang + '|names}}==', pronunc: '', pos_header: '===' + params.pos.charAt(0).toUpperCase + params.pos.substr(1) + '===', head: '', def: '', declension: '', conjugation: '' }; get_preload_text[params.lang](params, entry); entry_text = entry.lang_header + (entry.pronunc ? '\n\n===Pronunciation===\n' + entry.pronunc : '') + '\n\n' + entry.pos_header + '\n' + entry.head + '\n\n' + '# ' + entry.def + (entry.declension ? '\n\n====Declension====\n' + entry.declension : '') + (entry.conjugation ? '\n\n====Conjugation====\n' + entry.conjugation : ''); return entry_text; }	catch (e) {		if (e instanceof PreloadTextError) return false; else throw e;	} }

// Exception class function PreloadTextError {	this.name = 'PreloadTextError'; this.message = 'Could not generate a form-of entry for this language and form.'; }

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

/* * Generation rules for each language. * * Each function has two parameters. * params holds the parameters given in the template. * entry holds the various parts of the entry to be created. * * The function's task is to provide new values for some of the parts of the new entry. * In most cases, entry.def (the definition line) will be overridden, but the headword (entry.head) * or even the part-of-speech or language headers can be overridden if necessary. * * If the function is not able to handle the current form for whatever reason, throw an exception: * throw new PreloadTextError; */

// Azeri get_preload_text.az = function (params, entry) {		entry.def = '{'+'{inflection of|' + params.origin + '||';

if (form == 'definite-plural') entry.def += 'definite|p'; else if (form == 'definite-accusative') entry.def += 'definite|acc|s'; else if (form == 'plural-definite-accusative') entry.def += 'definite|acc|p'; else if (form == 'dative') entry.def += 'dat|s'; else if (form == 'plural-dative') entry.def += 'dat|p'; else if (form == 'locative') entry.def += 'loc|s'; else if (form == 'plural-locative') entry.def += 'loc|p'; else if (form == 'ablative') entry.def += 'abl|s'; else if (form == 'plural-ablative') entry.def += 'abl|p'; else if (form == 'genitive') entry.def += 'definite|gen|s'; else if (form == 'plural-genitive') entry.def += 'definite|gen|p'; entry.def += '|lang=' + params.lang + '}}'; }

// Catalan get_preload_text.ca = function (params, entry) {		var template = { 'plural':'plural of', 'masculine-plural': 'masculine plural of', 'feminine':'feminine of', 'feminine-plural': 'plural of'}; if (!template[params.form]) throw new PreloadTextError; entry.head = '{'+'{head|' + params.lang + '|' + params.pos + ' form}}'; entry.def = ''; };

// English get_preload_text.en = function (params, entry) {		switch (params.form) {			case 'comparative': entry.def = '{'+'{en-comparative of|' + params.origin + (params.pos != 'adjective' ? '|POS=' + params.pos : '') + '}}'; break; case 'superlative': entry.def = '{'+'{en-superlative of|' + params.origin + (params.pos != 'adjective' ? '|POS=' + params.pos : '') + '}}'; break; case 'third-person-singular': entry.def = '{'+'{en-third-person singular of|' + params.origin + '}}'; break; case 'simple-past': entry.def = '{'+'{en-simple past of|' + params.origin + '}}'; break; case 'simple-past-and-participle': entry.def = '{'+'{en-past of|' + params.origin + '}}'; break; default: entry.def = '{'+'{' + params.form.replace(/-/g, ' ') + ' of|' + params.origin + '|lang=' + params.lang + '}}'; }	};

// Esperanto get_preload_text.eo = function (params, entry) {		var stem = params.origin.substr(0, params.origin.length - 1); var ending = params.origin.substr(params.origin.length - 1); if (ending != 'o' && ending != 'a') throw new PreloadTextError; var is_proper = params.pos == 'proper noun'; switch(params.form) {			case 'uncountable-accusative': entry.def = stem + '|' + ending + 'n|unc=yes'; break; case 'plural': entry.def = stem + '|' + ending + 'j' + (is_proper ? '-proper' : ''); break; case 'accusative': entry.def = stem + '|' + ending + 'n' + (is_proper ? '-properpl' : ''); break; case 'accusative-plural': entry.def = stem + '|' + ending + 'jn' + (is_proper ? '-properpl' : ''); break; default: throw new PreloadTextError; }		entry.def = '{'+'{eo-form of|' + entry.def + '}}' };

// Spanish get_preload_text.es = function (params, entry) {		var template = { 'plural':'plural of', 'masculine-plural': 'masculine plural of', 'feminine':'feminine of', 'feminine-plural': 'plural of'}; if (!template[params.form]) throw new PreloadTextError; entry.head = '{'+'{head|' + params.lang + '|' + params.pos + ' form}}'; entry.def = ''; };

// Persian get_preload_text.fa = function (params, entry) {		entry.head = '{'+'{fa-word' + (params.transliteration ? ('|tr=' + params.transliteration) : '') + '}}' switch (params.form) {			case 'comparative': entry.def = '{'+'{fa-adj-form|c|' + params.origin + '}}'; break; case 'superlative': entry.def = '{'+'{fa-adj-form|s|' + params.origin + '}}'; break; default: throw new PreloadTextError; }	};

// French get_preload_text.fr = function (params, entry) {		var template = { 'plural':'plural of', 'masculine-plural': 'masculine plural of', 'feminine':'feminine of', 'feminine-plural': 'plural of'}; if (!template[params.form]) throw new PreloadTextError; entry.head = '{'+'{head|' + params.lang + '|g=?-p|' + (params.pos == 'noun' ? 'plural' : params.pos + ' form') +'	}}'; entry.def = ''; };

// Dutch get_preload_text.nl = function (params, entry) {		switch (params.form) {			case 'plural': entry.head = '{'+'{head|nl|noun plural form}}'; entry.def = ''; break; case 'diminutive': entry.head = '{'+'{nl-noun-dim}}'; entry.def = ''; break; default: throw new PreloadTextError; }	};

// Polish get_preload_text.pl = function (params, entry) {		var formof = params.form.replace(/-/g, ' '); formof = formof.replace('third person', 'third-person'); formof = formof.replace('simple past and participle', 'past'); entry.def = '{'+'{' + formof + ' of|' + params.origin + '|lang=pl' + (params.pos == 'adverb' ? '|POS=adverb' : '') + '}}'; };

get_preload_text.sl = function (params, entry) {		switch (params.form) {			case 'comparative': case 'superlative': entry.pronunc = ''; entry.head = '{'+'{sl-' + (params.pos == 'adverb' ? 'adv' : 'adj') + '-' + (params.form == 'comparative' ? 'comp' : 'sup') + '|' + params.target + '}}'; // If there is a comma in the head, assume it has multiple accented variants. // Add a link with an alternative display form instead. entry.def = '';				// If it's an adjective, add a declension table if (params.pos == 'adjective') {					var stem = params.target.substr(0, params.target.length - 1); var ending = params.target.substr(params.target.length - 1); // Adjective comparatives and superlatives must always end in -i if (ending != 'i') throw new PreloadTextError; entry.declension = ''; }				break; default: throw new PreloadTextError; }	}

// Swedish get_preload_text.sv = function (params, entry) {		if (! (params.form.match(/^superlative/) || params.form.match(/^comparative/) || params.form.match(/^positive/)) ) throw new PreloadTextError; var template = false; switch (params.form + '/' + params.gender) {			case 'positive/n': template = 'sv-adj-form-abs-indef-n'; break; case 'positive/m': template = 'sv-adj-form-abs-def-m'; break; case 'positive-definite/': template = 'sv-adj-form-abs-def'; break; case 'positive-plural/': template = 'sv-adj-form-abs-pl'; break; case 'comparative/': if (params.pos == 'adjective') template = 'sv-adj-form-comp'; else template = 'sv-adv-form-comp'; break; case 'superlative-attributive/m': template = 'sv-adj-form-sup-attr-m'; break; case 'superlative-attributive-definite/': template = 'sv-adj-form-sup-attr'; break; case 'superlative-attributive-plural/': template = 'sv-adj-form-sup-attr-pl'; break; case 'superlative-predicative/': template = 'sv-adj-form-sup-pred'; break; case 'superlative/': template = 'sv-adv-form-sup'; break; default: throw new PreloadTextError; }		entry.def = '{'+'{' + template + '|' + params.origin + '}}'; }

// Tajik get_preload_text.tg = function (params, entry) {		entry.head = '{'+'{tg-word' + (params.transliteration ? ('|tr=' + params.transliteration) : '') + '}}' switch(params.form) {			case 'comparative': entry.def = '{'+'{tg-adj-form|c|' + params.origin + '}}'; break; case 'superlative': entry.def = '{'+'{tg-adj-form|s|' + params.origin + '}}'; break; default: throw new PreloadTextError; }	};

// Turkish get_preload_text.tr = function (params, entry) {		entry.def = '{'+'{inflection of|' + params.origin + '||';

if (form == 'definite-plural') entry.def += 'definite|p'; else if (form == 'definite-accusative') entry.def += 'definite|acc|s'; else if (form == 'plural-definite-accusative') entry.def += 'definite|acc|p'; else if (form == 'dative') entry.def += 'dat|s'; else if (form == 'plural-dative') entry.def += 'dat|p'; else if (form == 'locative') entry.def += 'loc|s'; else if (form == 'plural-locative') entry.def += 'loc|p'; else if (form == 'ablative') entry.def += 'abl|s'; else if (form == 'plural-ablative') entry.def += 'abl|p'; else if (form == 'genitive') entry.def += 'definite|gen|s'; else if (form == 'plural-genitive') entry.def += 'definite|gen|p'; entry.def += '|lang=' + params.lang + '}}'; }

// Yiddish get_preload_text.yi = function (params, entry) {		switch (params.form) {			case 'plural': entry.head = '{'+'{head|' + params.lang + (params.transliteration ? '|tr=' + params.transliteration : '') + '}}'; entry.def = '{'+'{plural of|' + params.origin + '|lang=' + params.lang + '}}'; break; case 'past-participle': entry.head = '{'+'{head|' + params.lang + '|past participle' + (params.transliteration ? '|tr=' + params.transliteration : '') + '}}'; entry.def = '{'+'{past participle of|' + params.origin + '|lang=' + params.lang + '}}'; break; default: throw new PreloadTextError; }	};

/* * "External" generation rule definitions. * * These are used when there is no "internal" rule for a given situation. */

/* * Which template should be used for "external" rule definitions? * * Check if we know of a template that will do the job. * Use an explicit list to make it harder to subvert. */ function get_preload_template (form, lang, link) {	var prefix = 'User:Conrad.Irwin/creation.js/';

if (lang == 'da' && form.match(/genitive/)) {		return prefix + 'inflNoun'; }	else if (lang == 'he') {		switch (form) {			case 'plural': case 'construct': return prefix + 'inflNoun'; default: return false; }	}	else // Defaults {		switch (form) {			case 'plural' : case 'diminutive' : case 'genitive' : case 'diminutive-plural' : case 'genitive-and-plural': return prefix + 'basicNoun'; case 'plural-definite': case 'plural-indefinite': case 'singular-definite': case 'vocative': case 'singular-vocative': case 'plural-vocative': return prefix + 'inflNoun'; case 'third-person-singular': case 'present-participle': case 'simple-past': case 'past-participle': if(lang=='da') return prefix+'inflForm'; case 'simple-past-and-participle': return prefix + 'basicVerb'; case 'present': case 'past': case 'infinitive': case 'imperative': return prefix + 'inflForm'; case 'positive': return prefix + 'positiveAdjective'; case 'comparative': case 'superlative': case 'inflected-form': case 'exaggerated': if ((lang == 'hu' || lang == 'cs' || lang == 'sl') && get_part_of_speech(link) == 'adverb') return prefix + 'basicAdverb'; return prefix + 'basicAdjective'; default: return false; }	} }

/* * Rules to full in each of the values in the template subpage. * * The rules consist of a series of "set" functions. These set the parameters that * are then used in one of the templated subpages of the script to make an entry. * See the documentation page for a full list of subpages. * * Each function returns a "variable", which acts like a wrapper for a defined parameter. * For example, returning variable('lang', 'en') will cause any instances of '' * in the subpage template to be replaced with 'en'. */

// The page's language. function set_lang (lang) {	return variable ('lang', lang); }

// The optional language parameter to give to a template (either '' for english, or '|lang=xx') function set_template_lang (lang, form) {	// Did I say the last one was horrible?... if (lang == 'gd' && form == 'genitive-and-plural') {		return variable('template-lang', '|lang=gd}}%0A%23 {'+'{plural of|' + wgTitle + '|lang=gd'); }	else {		return variable ('template-lang', '|lang=' + lang); } }

//The gender template with a leading space (or an empty string if no gender) function set_gender_template (gender, lang) {	if (lang == 'he') return variable ('gender-template', ' {'+'{romanization of Hebrew}}')

if (lang == 'bg') return variable ('gender-template', ' ['+'[Category:Bulgarian terms lacking transliteration]]') gender = gender.replace('pl','p').replace(/([mfnc])p/, '$1-p');

if (gender.length == 0) {		return variable ('gender-template', ''); }	else {		return variable ('gender-template', '{'+'{'+ gender + '}}'); } }

//The optional |g= argument to { {head}} function set_template_gender (gender, lang, form) {	if (form == 'diminutive-plural') return variable('template-gender','|plural=1'); if (form == 'plural' && gender.indexOf('p') < 0) gender += 'p';

gender = gender.replace('pl','p').replace(/([mfnc])p/, '$1-p');

if (gender.length == 0) return variable('template-gender',''); else return variable('template-gender', '|g=' + gender); }

//Form of templates for genders. These are the ones that exist, if we need others, //either create them or use { {form-of}} manually. function gender_form (gender) {	if (gender == 'mpl') {		return 'masculine plural'; }	else if (gender == 'f') {		return 'feminine'; }	else if (gender == 'fpl') {		return 'feminine plural'; }	else if (gender == 'n') {		return 'neuter'; }	else if (gender == 'mfpl') {		return 'plural'; }	else {		throw new Error('Not simple gender?!'); }

}

// The page name that the entry is a form of. // Returns in PIPED format. Which, while kind of bad, works as either embedded in %s or { {template|%s}} // and most templates take an optional display parameter as the first after the link. function set_origin (given, lang) {	//Remove links from given parameters, and unencode underscores to spaces if (given) {		given = given.replace(/\[\[([^\|\]])*\|?([^\]]+)\]\]/g,'$2').replace(/_/g,' '); return variable ('origin', wgTitle + '|' + given); }

return variable ('origin', wgTitle); }

// The page we are about to create with links on individual words. function set_pagename_linked_and_template_head (link, lang, form) {	var pagename = (link.innerText || link.textContent);

var op = pagename; pagename = pagename.replace (/([ -])/g,']]$1[[')

if (op != pagename) {		pagename = +pagename+; return variable('pagename-linked', pagename) + variable('template-head','|head=' + pagename) }

return variable('pagename-linked', pagename) + variable('template-head',''); }

// Script code function set_template_sc (lang) {	var sc; switch (lang) {		case 'he': sc = 'Hebr'; break; default: return variable('template-sc',''); }	return variable('template-sc','|sc='+sc) }

//The form-of template we are to use function set_form_template (form, lang, gender, link) {	var formof = form.replace(/-/g,' ');

if (lang == 'eo') {		return variable('form-template', 'eo-form of'); }	else if (formof == 'construct') {		return variable('form-template', 'form of|' + formof.replace('-',' ') + ' form'); }	else if (lang == 'da') {		return variable('form-template', 'form of|' +formof.replace('-',' ')); }	if (formof == 'positive') {		formof = gender_form (gender) if (formof == 'plural') {			return variable('form-template','form of|plural'); }	}	else {		formof = formof.replace('third person', 'third-person'); formof = formof.replace('simple past and participle', 'past'); }

if (formof == 'diminutive plural') return variable('form-template', 'diminutive of|plural=1');

if (lang == 'gd' && formof == 'genitive and plural') {		formof = 'genitive' }	formof = formof + ' of'; return variable('form-template', formof); }

function set_part_of_speech (link,lang,form) {	if (lang=='da') return variable('part-of-speech', 'verb'); else return variable('part-of-speech', get_part_of_speech(link)); }

/* * Create a "variable". * * This is a template-like replacement of text wrapped in  with something else. */ function variable (name, replacement) {	return get_escape ('s~{'+'{'+'{' + clean_regexp (name) + '}}}~' + clean_variable (replacement) + '~g;') }

//AutoEdit irritatingly doesn't undo %XX encodings, so we can't send them. //FIXME: Not a lot we can do about &s maybe patch AutoEdit. function get_escape (get) {	return get.replace (/&/g,'%26'); //This shouldn't do anything to variables. }

function clean_regexp (re) {	return re.replace (/([\\\*\+\[\]\{\}\(\)\.~])/g,'\\$1'); }

function clean_variable (va) {	return va.replace (/([\\~])/g,'\\$1').replace(/&/g,'{'+'{subst:⅋}}').replace(/#/,'{'+'{subst:♯}}'); //Yucky HACK }

/* * 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. */ $( 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= 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); }	// If that doesn't work, then try generating an entry "externally" by using one of // the script's subpages as a template. else if (preload = get_preload_template(params.form, params.lang, link)) {		workerHref = '&preload=' + encodeURIComponent(preload) + '&autoedit=' + ((params.lang == 'da') ? set_part_of_speech (link, params.lang, params.form) : '') + set_lang (params.lang) + set_template_lang (params.lang, params.form) + set_gender_template (params.gender, params.lang) + set_template_gender(params.gender, params.lang, params.form) + set_origin (params.origin == params.origin_pagename ? false : params.origin, params.lang2 ? params.lang2 : params.lang) + set_pagename_linked_and_template_head (link, params.lang, params.form) + set_form_template (params.form, params.lang, params.gender, link) + set_template_sc (params.lang) }	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 + '&preloadsummary=' + encodeURIComponent('Creating ' + params.form + ' form of ' + params.origin_pagename + ' (Accelerated)' ) + '&preloadminor=true'; }

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

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) {	var node = link; while(node) {		while (node.previousSibling) {			node = node.previousSibling; if (node.nodeType == 1 && node.nodeName.match(/^[hH][3456]$/)) {				return node.firstChild.innerHTML.replace(/^[1-9.]* /,'').toLowerCase; }		}		node = node.parentNode; }	throw new Error('This entry seems to be formatted incorrectly. Does it have a language and part-of-speech header?'); }