Jump to content

User:V111P/js/wikiTranslTools.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by V111P (talk | contribs) at 06:40, 6 June 2012 (HomeWiki link bug fix). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* Wiki Translation Tools v. 1.01 */
"use strict"
var wikiTranslTools = (function ()
{
	var THIS_ARTICLE = wgPageName.replace(/_/g, ' ');

	/*******
	 * Home-Wiki Constants - need to be set with init() or setHomeWiki()
	 ******/
 	var HomeWiki = {
		LANG: '',
		SERVER: '',
		FA_LINK_TEMPLATE: 'Link FA',
		GA_LINK_TEMPLATE: 'Link GA',
		TRANSLATED_PAGE_TEMPLATE: ''
	}

	var SKIN = { // values must be CSS/jQuery selectors
		OUTPUT_AREA: '#contentSub',
		PERMALINK: '#t-permalink a', // leave empty to use the document URL and a built-in MediaWiki variable
		INTERWIKI_DIV: '#p-lang',
		CAT_LINKS_ID: '#mw-normal-catlinks' // id of non-hidden categories <div>.
		//  Leave empty to use the built-in wgCategories array (which includes hidden cats) */
	}

	/*******
	 * Local-Wiki Constants
	 ******/
	var ThisWiki = {
		LANG: wgContentLanguage,

		// These strings are used to find out which articles have a 'Good' or 'Featured' status
		//  in this and in the other Wikipedias.
		FEAT_ARTICLE: {
			TagIdBeginning: 'interwiki-',
			TagIdEnding:    '-fa',
			TagClass:       '',
			CatName:        'Featured articles'
		},

		GOOD_ARTICLE: {
			TagIdBeginning: 'interwiki-',
			TagIdEnding: 	'-ga',
			TagClass:       '',
			CatName:        'Good articles'
		},

		CAT_NS: wgFormattedNamespaces[14] // The local name of the Category namespace
	}


	/*******
	 * Other Constants
	 ******/
	var TA_Rows = 10; // number of rows for the output textarea
	var TA_Cols = 80; // this has no effect in Monobook and other skins

	// if the article has that many categories or less, they will be auto-expanded
	//   when the Category Browser is shown for the first time on the page.
	var MaxCatsToAutoExpand = 5;

	// Home wiki links will be added only to these namespaces:
	// Namespases: main=0, user=2, wikipedia/wp=4, template=10, help=12, category=14, portal=100
	var NamespacesWithInterwikis = [0, 2, 4, 10, 12, 14, 100];

	var default_msgs = {
		error: 'error',
		OkButtonLabel: 'OK',
		interwikis: 'Interwikis',
		categories: 'Categories',
		trCatInterw: 'Tr/Cat/Interwikis',
		alreadyListed: 'already listed',
		linksTo: 'Links to',
		dblRedirect: 'double redirect'
	};

	var msgs = default_msgs;

	var nl = ($.browser.msie ? '\r\n' : '\n');  // new line

	/*******
	 * Private Variables
	 ******/
	var allCats; // used for the Category Browser

	var catsTranslInterw; // boolean,
		// "true" when getting categories, translated page template, and interwikis at the same time

	/* A class to hold info about a category */
	function Category(name, liElement)
	{
		this.name = name;
		this.liElement = liElement; // the innermost <li> within which the category's name is shown
	}

	// a shortcut for document.createTextNode()
	function textNode(str)
	{
		return document.createTextNode(str);
	}

	// very basic i18n
	function _(str)
	{
		return (msgs[str] || default_msgs[str] || '???');
	}


	/*************************
	 ***  TRANSLATED PAGE TEMPLATE
	 ***
	 *** showTranslatedPageTemplate() - public
	 *** getTranslatedPageTemplate()
	 ***/


	/* PUBLIC */
	// called when the user clicks on the {{Translated page}} portlet link.
	function showTranslatedPageTemplate()
	{
		if ($('#wikiCodeBox').remove().attr('name') == 'translationTemplate')
			return;
		catsTranslInterw = false;
		displayCode(getTranslatedPageTemplate(), 'translationTemplate');
	}


	function getTranslatedPageTemplate()
	{
		var revisionId;
		var permalink = [];
		if (SKIN.PERMALINK)
			permalink = $(SKIN.PERMALINK);
		if (permalink[0])
			revisionId = permalink.attr('href').match(/oldid=(.+)/)[1];
		else
		{
			var regExpResult = location.href.match(/oldid=([^&#]+)/);
			revisionId = regExpResult && regExpResult[1];
			if (!revisionId)
				revisionId = wgCurRevisionId;
		}
		return '{{' + HomeWiki.TRANSLATED_PAGE_TEMPLATE + '|'
			+ ThisWiki.LANG + '|' + THIS_ARTICLE + '|' + revisionId + '}}';
	}


	/*************************
	 ***  INTERWIKIS
	 ***
	 *** void   showInterwikiCode() - public
	 *** string getInterwikiCode()
	 *** string goodArticleLinks(langArr, goodArticleStrings, homeGALinkTemplate)
	 ***/


	/* PUBLIC */
	// called when the user clicks on the Interwikis portlet link
	function showInterwikiCode()
	{
		if ($('#wikiCodeBox').remove().attr('name') == 'interwikis')
			return;
		catsTranslInterw = false;
		displayCode(getInterwikiCode(), 'interwikis');
	}


	// reads the interwikis from the element with the specified in SKIN.INTERWIKI_DIV id
	//  calls goodArticleLinks() to check for 'Good' and 'Featured' articles
	function getInterwikiCode()
	{
		var links = [], keys = [];

		var liElements = $(SKIN.INTERWIKI_DIV + ' a').each(function (){
			var result = $(this).attr('href').match(/\/\/([^\.]+)\.[^\/]+\/wiki\/(.+)/);
			if (!result)
				return;
			var lang = result[1];
			var title = decodeURI(result[2]).replace(/_/g, ' ');
			if (lang != HomeWiki.LANG) {
				links[lang] = title;
				keys.push(lang);
			}
		});

		/* adding this page's wikilink to the array */
		links[ThisWiki.LANG] = THIS_ARTICLE;
		keys.push(ThisWiki.LANG);
		keys.sort();

		var interwikisStr = '';
		for (var i = 0; i < keys.length; i++)
			interwikisStr += '[[' + keys[i] + ':' + links[keys[i]] + ']]' + nl;

		var featArticlesStr = goodArticleLinks(keys, ThisWiki.FEAT_ARTICLE, HomeWiki.FA_LINK_TEMPLATE);
		var goodArticlesStr = goodArticleLinks(keys, ThisWiki.GOOD_ARTICLE, HomeWiki.GA_LINK_TEMPLATE);

		return featArticlesStr + goodArticlesStr + interwikisStr;
	}


	// this function is used to get both the "Good Articles" and the "Featured Articles"
	function goodArticleLinks(langArr, goodArticleStrings, homeGALinkTemplate)
	{
		var goodArticleArr = [];
		for (var i = 0; i < langArr.length; i++)
		{
			var goodTag = $('#' + goodArticleStrings.TagIdBeginning
				+ langArr[i]
				+ goodArticleStrings.TagIdEnding);

			if (goodTag[0])
				if (goodArticleStrings.TagClass)
					goodTag = goodTag.filter('.' + goodArticleStrings.TagClass);

			if (goodTag[0])
				goodArticleArr.push(langArr[i]);
		}

		// check and add this article
		for (var i = 0; i < wgCategories.length; i++) {
			if (wgCategories[i] == goodArticleStrings.CatName) {
				goodArticleArr.push(ThisWiki.LANG);
			}
		}

		goodArticleArr.sort();

		var goodArticleStr = '';
		for (var i = 0; i < goodArticleArr.length; i++) {
			goodArticleStr += '{{' + homeGALinkTemplate + '|' + goodArticleArr[i] + '}}' + nl;
		}

		if (goodArticleStr) goodArticleStr += nl;

		return goodArticleStr;
	}


	/*************************
	 ***  CATEGORIES
	 ***
	 *** void catsTranslInterw() - public
	 *** void categories() - public
	 *** void createTheCategoryBrowser()
	 *** JQueryObject createExpandCatLink()
	 *** void expandCat(HTMLElementObject startCatExpandLinkEl)
	 *** void catReceived(Category cat)
	 *** void showCatParents(Category cat, String[] parents, String homeWikiCat)
	 *** void catsOK(HTMLFormElement frm)
	 *** void afterCats(String catsStr)
	 ***/


	/* PUBLIC */
	// called when the user clicks on the "Tr/Cat/Interwikis" portlet link
	function catsTranslInterw()
	{
		if ($('#wikiCodeBox').remove().attr('name') == 'categories')
			return; // remove the text area if it already contains the categories and do nothing else

		catsTranslInterw = true;
		if (!$('#catBrowserDiv').show()[0])
			createTheCategoryBrowser();
	}


	/* PUBLIC */
	// Called when the user clicks on the portlet link
	function categories()
	{
		// if the user previously clicked on the "Tr/Cat/Interwikis" portlet link, cancel that:
		catsTranslInterw = false;
		if ($('#wikiCodeBox').remove().attr('name') == 'categories')
			return; // remove the text area if it already contains the categories and do nothing else

		if ($('#catBrowserDiv').toggle()[0]) // if the Category Browser already exists, just show/hide it
			return;

		createTheCategoryBrowser();
	}


	// Called from categories() to create the Category Browser
	function createTheCategoryBrowser()
	{
		var catArr = [];

		// if possible, fill catArr with the non-hidden cats only,
		//  otherwise use wgCategories
		if (SKIN.CAT_LINKS_ID)
			catArr = $(SKIN.CAT_LINKS_ID + ' a').map(function(i) {
				if (i == 0) return null; // skip the 'Categories:' link
				return getInnerText(this);
			}).toArray();
		else
			catArr = wgCategories;

		if (catArr.length == 0)
		{
			afterCats('');
			return;
		}

		allCats = {};

		// create the main UL and sub li's with the category names
		var top_ul = $('<ul/>');
		var catBrowserDiv = $('<div/>', {
			css: {color: '#000', backgroundColor: '#f4f4f4', fontSize: 'small'},
			id: 'catBrowserDiv'
		});

		var top_li;
		for (var i = 0; i < catArr.length; i++)
		{
			var expandLink = createExpandCatLink();

			top_li = $('<li/>').append(expandLink, textNode(' '), '<span>' + catArr[i] + '</span>');
			allCats[catArr[i]] = new Category(catArr[i], top_li);

			top_ul.append(top_li);

			if (catArr.length <= MaxCatsToAutoExpand)
				expandLink.click();
		}

		var catForm = $('<form/>', {
			id: 'catForm',
			submit: function() {
				catsOK(this);
				return false;
			}
		})
		.append(top_ul, '<input type="submit" value="' + _('OkButtonLabel') + '"/>');

		catBrowserDiv.append(catForm);
		$(SKIN.OUTPUT_AREA).append(catBrowserDiv);

	} // translateCategories()


	function createExpandCatLink()
	{
		return $('<a/>', {
			text: '[+]',
			href: '#',
			click: function() {
				expandCat(this);
				return false;
			},
			css: {textDecoration: 'none'}
		});
	}


	// Called when the user clicks on a [+] expand link in the Category Browser
	// It makes an AJAX request for the specified category page,
	//  and calls showCatParents() to display the obtained information
	// (parent cats and (if there is one) the home-wiki cat)
	function expandCat(startCatExpandLinkEl)
	{
		var startCatLink = $(startCatExpandLinkEl);
		var catSpan = $('span', startCatLink.parent()); // it contains the name of the cat to be expanded

		startCatLink.empty().append(textNode('...')); // replace "[+]" with "..."
		startCatLink.attr('class', 'waitingExpandLink');
		var cat = allCats[getInnerText(catSpan[0])];

		$.ajax({
			url: wgServer + wgScriptPath + '/index.php?title='
				+ ThisWiki.CAT_NS + ':' + cat.name + '&action=raw',
			dataType: 'text',
			success: catReceived(cat),  // bug in jQuery calls success even if Internet is disconected
			error: function (XMLHttpRequest) {
					showCatParents(cat);
			}
		});
	}


	// creates and returns a function to be called when the requested Category page code is received
	function catReceived(cat)
	{
		return function(data) {

			var tempArr = (HomeWiki.LANG
				? data.match('\\[{2}' + HomeWiki.LANG + ':([^\\]]+)')
				: null);
			var homeWikiCat = (tempArr ? tempArr[1] : '');
			var parents = [];

			var re = new RegExp(
				'\\[{2}' + ThisWiki.CAT_NS + ':([^\\]\\|]+)',
				'g'
			);
			while ((tempArr = re.exec(data)) != null)
			{
				parents.push(tempArr[1]);
			}

			showCatParents(cat, parents, homeWikiCat);
		}
	}


	// called by expandCat() to add the parent categories
	//  of the specified category to the displayed list.
	function showCatParents(cat, parents, homeWikiCat)
	{
		var top_li = cat.liElement;

		$('.waitingExpandLink', top_li).remove();

		if (homeWikiCat)
		{
			var homeWikiLink = $('<a/>', {
				text: homeWikiCat,
				href: wgServer + '/wiki/' + homeWikiCat,
				target: '_blank'
			});

			top_li.append(textNode(' – '),
				'<input type="checkbox" name="homecats" value="' + homeWikiCat + '"/>',
				textNode(' ' + HomeWiki.LANG + ':'),
				homeWikiLink);
		}
		else if (parents && parents.length > 0)
		{
			var new_ul = $('<ul/>');

			var new_li;
			var alreadyListed;
			for (var i = 0; i < parents.length; i++)
			{
				new_li = $('<li/>');

				alreadyListed = false;

				if (allCats[parents[i]])
					alreadyListed = $('<em>(' + _('alreadyListed') + ')</em>');
				else
				{
					new_li.append(createExpandCatLink(), textNode(' '));
					allCats[parents[i]] = new Category(parents[i], new_li);
				}

				new_li.append('<span>' + parents[i] + '</span>');
				if (alreadyListed)
				{
					new_li.append(textNode(' '), alreadyListed);
				}
				new_ul.append(new_li);
			}

			top_li.append(new_ul);
		} // if (parents.length > 0)
		else // if no home-wiki cat and no parent cats found, create a link to the cat,
			 //  so the user can check manually
		{
			var catSpan = $('span', top_li).empty();
			catSpan.append($('<a/>', {
				href: wgServer + '/wiki/'
					+ ThisWiki.CAT_NS + ':' + cat.name,
				target: '_blank',
				text: cat.name
			}))
			.append(textNode(' '),
				// no parents arr is passed if the cat doesn't exist (404 or other error received)
				$('<em>(' + _('error') + ')</em>')
			);
		}
	}


	// called when the user press the OK button in the "Category Browser"
	function catsOK(frm)
	{
		$('#catBrowserDiv').hide();

		var homeCats = $('input:checkbox[name=homecats]:checked', frm).map(function(){
			return this.value;
		}).toArray();

		if (homeCats.length == 0)
		{
			if (catsTranslInterw)
				afterCats('');
			return;
		}

		var catStr = '[[' + homeCats.join(']]'+nl+'[[') + ']]';

		if (catsTranslInterw)
			afterCats(catStr);
		else
			displayCode(catStr, 'categories');
	}


	function afterCats(catsStr)
	{
		if (!catsTranslInterw)
			return;

		catsTranslInterw = false;

		displayCode(getTranslatedPageTemplate() + nl + nl
			+ (catsStr ? catsStr + nl + nl : '')
			+ getInterwikiCode(), 'categories');
	}


	/*************************
	 ***  HOME-WIKI LINK
	 ***
	 *** homeWikiLinks() - public
	 *** findHomeWikiLink(HTMLElementObject clickedLinkEl)
	 *** articleToSearchForHomeWikiLinkIn_Received(JQueryObject clickedLink)
	 ***/


	/* PUBLIC */
	// called when the user clicks on the "Links to (language code)" portlet link
	function homeWikiLinks()
	{
		var hWLs = $('.homeWikiLink');
		if (hWLs.length > 0)
		{ // if already shown, hide them and return
			hWLs.toggle();
			return;
		}

		$('#bodyContent a').not('#catBrowserDiv a').not('#' + SKIN.CAT_LINKS_ID + ' a').not('a.external')
		.filter('[href^="/wiki/"]').after(function () {
			var article = this.href.match(/wiki\/([^#]+)/);

			if (!article)
				return null;
			article = article[1];

			// Check if the namespace is in the array of approved namespaces: NamespacesWithInterwikis
			var ns = article.match(/[^:]+(?=:)/);
			if (ns)
			{
				var nsNum = wgNamespaceIds[ns[0].toLowerCase()];
				if (nsNum && ($.inArray(nsNum, NamespacesWithInterwikis) == -1))
					return null;
			}

			var span = $('<sup>', {
				text: ' [[',
				'class': 'homeWikiLink reference'
			}).append($('<a/>', {
				text: HomeWiki.LANG + ':?',
				href: '#',
				data: {articleName: article},
				click: function () {
					findHomeWikiLink(this);
					return false;
				}
			})).append(textNode(']]'));

			return span;
		});
	}


	// This function is called when the user clicks on one of the [[lang:?]] links
	function findHomeWikiLink(clickedLinkEl)
	{
		var clickedLink = $(clickedLinkEl);
		var articleName = clickedLink.data('articleName');

		$.get(wgServer + wgScriptPath + '/index.php?title='
			+ articleName + '&action=raw',
			articleToSearchForHomeWikiLinkIn_Received(clickedLink)
		);
	}


	// creates and returns a function to be called when the requested article
	//  (which is going to be searched for an interwiki link to a Home Wiki article) is received
	function articleToSearchForHomeWikiLinkIn_Received(clickedLink)
	{
		return function(data) {
			var resultArr;
			var homeLink;

			var resultArr = data.match('\\[{2}' + HomeWiki.LANG + ':([^\\]]+)]');
			if (!resultArr)
			{
				$.trim(data);
				if (data.charAt(0) == '#')
				{
					if (clickedLink.data('redirected'))
						clickedLink.replaceWith($('<span/>', {
							text: _('dblRedirect'),
							css: {fontStyle: 'italic'}
						}));
					else
					{
						var redirTo = data.match(/\[\[([^\]]+)/);
						if (!redirTo)
							clickedLink.replaceWith($('<span/>', {
								text: _('error'),
								css: {fontStyle: 'italic'}
							}));
						else
						{
							clickedLink.data('articleName', redirTo[1].match(/[^#]+/));
							clickedLink.data('redirected', '1');
							clickedLink.before('<span title="'+redirTo[1]+'">&gt;</span>');
							findHomeWikiLink(clickedLink[0]);
						}
					}
				}
				else
					clickedLink.replaceWith($('<span/>', {
						text: HomeWiki.LANG,
						css: {textDecoration: 'line-through'}
					}));
			}
			else
			{
				var homeWikiPage = resultArr[1];

				var newLink = $('<a/>', {
					href: HomeWiki.SERVER + '/wiki/' + homeWikiPage,
					target: '_blank',
					text: HomeWiki.LANG + ':'
				});

				var input = $('<input type="text" style="vertical-align: bottom; direction: ltr;">').attr({
					value: homeWikiPage,
					size: Math.floor(homeWikiPage.length * 4/3),
					readonly: 'readonly'
				});
				clickedLink.after(input);
				clickedLink.replaceWith(newLink);
				input.select();
			}
		}
	}


	/*************************
	 ***  Other Functions
	 ***
	 *** void displayCode(String str, String name)
	 *** void addPortletLinks()
	 *** void init(attr) - public
	 *** void setHomeWiki(obj) - public
	 *** void setSkin(obj) - public
	 ***/

	function displayCode(str, name)
	{
		$('#catBrowserDiv').hide();
		var wikiCodeBox = $('#wikiCodeBox');
		if (wikiCodeBox.show()[0])
			wikiCodeBox.text = str;
		else
		{
			wikiCodeBox = $('<textarea/>', {
				id: 'wikiCodeBox',
				text: str,
				name: name,
				css: {direction: 'ltr', width: '80%', display: 'block'},
				cols: TA_Cols,
				rows: TA_Rows,
				readonly: 'readonly'
			}).appendTo(SKIN.OUTPUT_AREA).select().focus().scrollTop();
		}
	}


	function addPortletLinks()
	{
		if (wgAction != 'view')
			return;

		if (wgCanonicalNamespace != 'Special' && wgCanonicalNamespace != 'MediaWiki')
			addPortletLink('p-tb', 'javascript:wikiTranslTools.showTranslatedPageTemplate(); void(0);',
				'{{' + (HomeWiki.TRANSLATED_PAGE_TEMPLATE || 'Translated page') + '}}',
				'translatedPageTemplateLink',
				'{{' + (HomeWiki.TRANSLATED_PAGE_TEMPLATE || 'Translated page') + '}}');
		addPortletLink('p-tb', 'javascript:wikiTranslTools.showInterwikiCode(); void(0);',
			_('interwikis'),
			'interwikisLink',
			_('interwikis')
		);
		if (wgCategories && wgCategories.length > 0 && HomeWiki.LANG)
			addPortletLink('p-tb', 'javascript:wikiTranslTools.categories(); void(0);',
				_('categories'),
				'catBrowserLink',
				_('categories')
			);
		if (wgCanonicalNamespace != 'Special' && wgCanonicalNamespace != 'MediaWiki')
			addPortletLink('p-tb', 'javascript:wikiTranslTools.catsTranslInterw(); void(0);',
				_('trCatInterw'),
				'catTranslInterwLink',
				_('trCatInterw')
			);
		if (HomeWiki.LANG)
			addPortletLink('p-tb', 'javascript:wikiTranslTools.homeWikiLinks(); void(0);',
				_('linksTo') + ' ' + HomeWiki.LANG,
				'homeWikiLinksLink',
				_('linksTo') + ' ' + HomeWiki.LANG
			);
	}


	/* PUBLIC */
	function init(attr, noPortletLinks)
	{
		if (attr)
		{
			setHomeWiki(attr.homeWiki);
			msgs = attr.msgs || msgs;
			TA_Rows = attr.taRows || TA_Rows;
			MaxCatsToAutoExpand = (
				typeof attr.MaxCatsToAutoExpand == 'number'
				? attr.MaxCatsToAutoExpand
				: MaxCatsToAutoExpand);
			SKIN = attr.skin || SKIN;
		}
		if (!noPortletLinks)
			addPortletLinks();
	}


	/* PUBLIC */
	function setHomeWiki(obj)
	{
		HomeWiki = obj || HomeWiki;
		if (!HomeWiki.SERVER)
			HomeWiki.SERVER = wgServer.replace(ThisWiki.LANG, HomeWiki.LANG);
	}


	/* PUBLIC */
	function setSkin(obj)
	{
		SKIN = obj || SKIN;
	}


	/* All public member functions */
	return {
		init:                       init,
		setHomeWiki:                setHomeWiki,
		setSkin:                    setSkin,
		showTranslatedPageTemplate: showTranslatedPageTemplate,
		showInterwikiCode:          showInterwikiCode,
		categories:                 categories,
		catsTranslInterw:           catsTranslInterw,
		homeWikiLinks:              homeWikiLinks
	}
}());