MediaWiki:Common.js

Innen: Wiki Grepolis HU
A lap korábbi változatát látod, amilyen Trys Asgon (vitalap | szerkesztései) 2014. január 2., 21:54-kor történt szerkesztése után volt.
Jump to navigation

Megjegyzés: közzététel után frissítened kell a böngésződ gyorsítótárát, hogy lásd a változásokat.

  • Firefox / Safari: tartsd lenyomva a Shift gombot és kattints a Frissítés gombra a címsorban, vagy használd a Ctrl–F5 vagy Ctrl–R (Macen ⌘–R) billentyűkombinációt
  • Google Chrome: használd a Ctrl–Shift–R (Macen ⌘–Shift–R) billentyűkombinációt
  • Internet Explorer / Edge: tartsd nyomva a Ctrl-t, és kattints a Frissítés gombra, vagy nyomj Ctrl–F5-öt
  • Opera: Nyomj Ctrl–F5-öt
importScript_ = importScript
importScript = function (page, proj){
 if (!proj) importScript_(page)
 else {
   if (proj.indexOf('.')==-1) proj += '.wikipedia.org'
   importScriptURI('http://'+proj+'/w/index.php?action=raw&ctype=text/javascript&title='+encodeURIComponent(page.replace(/ /g,'_')))
 }
}
importMW = function (name) { importScript('MediaWiki:'+name+'.js') }


function LinkFA(){
 var pLang = document.getElementById('p-lang')
 if (!pLang) return
 var list = {
 'fa':'Эта статья является избранной',
 'fl':'Этот список или портал является избранным',
 'ga':'Эта статья является хорошей'}
 var iw = pLang.getElementsByTagName('li')
 for (var i=0; i<iw.length; i++)
   for (var s in list)
     if (document.getElementById(iw[i].className+'-'+s)){
       iw[i].className += ' ' + s.toUpperCase()
       iw[i].title = list[s] + ' в другом языковом разделе'
     }
}

function icqIcons(){
 var a, spans = document.getElementById('content').getElementsByTagName('span')
 for (var i=0; a=spans[i]; i++)
   if (a.className == 'ICQ')
     a.style.backgroundImage = "url('http://status.icq.com/online.gif?icq="+a.id+"&img=5&randseed="+Math.floor(Math.random()*10000000)+"')"
}

function editZeroSection(){
 var body = document.getElementById('bodyContent')
 if (!body) return
 var h2s = body.getElementsByTagName('H2')
 var h2 = h2s[0]
 if (!h2) return
 if (h2.parentNode.id == 'toctitle') h2 = h2s[1]
 if (!h2) return
 var span = h2.firstChild
 if (!span || span.className != 'editsection') return
 var zero = span.cloneNode(true)
 body.insertBefore(zero, body.firstChild)
 var a = zero.getElementsByTagName('a')[0]
 if (a.href.indexOf('&section=T') == -1 )  a.title = a.title.replace(/:.*$/,': 0')
 else a.title = 'Править секцию: 0'
 a.setAttribute('href', wgScript + '?title='+encodeURIComponent(wgPageName) + '&action=edit&section=0')
}


//Collapsiblе: [[ВП:СБ]]

var NavigationBarShowDefault = 2
var NavigationBarHide = '[-]'
var NavigationBarShow = '<+>'

var hasClass = (function (){
 var reCache = {}
 return function (element, className){
   return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className)
  }
})()

function collapsibleTables(){
 var Table, HRow,  HCell, btn, a, tblIdx = 0, colTables = []
 var allTables = document.getElementsByTagName('table')
 for (var i=0; Table = allTables[i]; i++){
   if (!hasClass(Table, 'collapsible')) continue
   if (!(HRow=Table.rows[0])) continue
   if (!(HCell=HRow.getElementsByTagName('th')[0])) continue
   Table.id = 'collapsibleTable' + tblIdx
   btn = document.createElement('span')
   btn.style.cssText = 'float:right; font-weight:normal; font-size:smaller'
   a = document.createElement('a')
   a.id = 'collapseButton' + tblIdx
   a.href = 'javascript:collapseTable(' + tblIdx + ');'
   a.style.color = HCell.style.color
   a.appendChild(document.createTextNode(NavigationBarHide))
   btn.appendChild(a)
   HCell.insertBefore(btn, HCell.childNodes[0])
   colTables[tblIdx++] = Table
 }
 for (var i=0; i < tblIdx; i++)
   if ((tblIdx > NavigationBarShowDefault && hasClass(colTables[i], 'autocollapse')) || hasClass(colTables[i], 'collapsed'))
     collapseTable(i)
}

function collapseTable (idx){
 var Table = document.getElementById('collapsibleTable' + idx)
 var btn = document.getElementById('collapseButton' + idx)
 if (!Table || !btn) return false
 var Rows = Table.rows
 var isShown = (btn.firstChild.data == NavigationBarHide)
 btn.firstChild.data = isShown ?  NavigationBarShow : NavigationBarHide
 var disp = isShown ? 'none' : Rows[0].style.display
 for (var i=1; i < Rows.length; i++)
    Rows[i].style.display = disp
}

function collapsibleDivs(){
 var navIdx = 0, colNavs = [], i, NavFrame
 var divs = document.getElementById('content').getElementsByTagName('div')
 for (i=0; NavFrame = divs[i]; i++) {
   if (!hasClass(NavFrame, 'NavFrame')) continue
   NavFrame.id = 'NavFrame' + navIdx
   var a = document.createElement('a')
   a.className = 'NavToggle'
   a.id = 'NavToggle' + navIdx
   a.href = 'javascript:collapseDiv(' + navIdx + ');'
   a.appendChild(document.createTextNode(NavigationBarHide))
   for (var j=0; j < NavFrame.childNodes.length; j++)
     if (hasClass(NavFrame.childNodes[j], 'NavHead'))
       NavFrame.childNodes[j].appendChild(a)
   colNavs[navIdx++] = NavFrame
 }
 for (i=0; i < navIdx; i++)
  if ((navIdx > NavigationBarShowDefault && !hasClass(colNavs[i], 'expanded')) || hasClass(colNavs[i], 'collapsed'))
     collapseDiv(i)
}

function collapseDiv(idx) {
 var div = document.getElementById('NavFrame' + idx)
 var btn = document.getElementById('NavToggle' + idx)
 if (!div || !btn) return false
 var isShown = (btn.firstChild.data == NavigationBarHide)
 btn.firstChild.data = isShown ? NavigationBarShow : NavigationBarHide
 var disp = isShown ? 'none' : 'block'
 for (var child = div.firstChild;  child != null;  child = child.nextSibling)
   if (hasClass(child, 'NavPic') || hasClass(child, 'NavContent'))
      child.style.display = disp
}

function voting12(){
 if (votingTrigger = document.getElementById('voting-trigger'))
  importScriptURI(wgServer+wgScript
   +'?title=MediaWiki:Voting12.js&action=raw&ctype=text/javascript&cversion='
   +encodeURIComponent(votingTrigger.innerHTML.replace(/\D+/g, '.')))
}

//Secure server
var metaBase = 'http://meta.wikimedia.org'
if (wgServer == 'https://secure.wikimedia.org') {
  importScript('MediaWiki:Common.js/secure.js','en')
  metaBase = 'https://secure.wikimedia.org/wikipedia/meta'
}


//Execution

if (wgCanonicalNamespace == 'Special'){

 if (/^(Uplo|Sear|Stat|Spec|Abus|Prefe)/i.test(wgCanonicalSpecialPageName))
   importMW(wgCanonicalSpecialPageName)

}else switch (wgAction){

 case 'history': importMW('History'); break

 case 'delete': importMW('Deletepage'); break

 case 'edit': case 'submit': importMW('Editpage') //and continue with the default: view, purge

 default:

  addOnloadHook(collapsibleDivs)
  addOnloadHook(collapsibleTables)
  importScriptURI(metaBase+'/w/index.php?title=MediaWiki:Wikiminiatlas.js&action=raw&ctype=text/javascript&smaxage=21600&maxage=86400')
  if (navigator.platform.indexOf('Win') != -1)
    importStylesheetURI('http://en.wikipedia.org/w/index.php?title=MediaWiki:Common.css/WinFixes.css&action=raw&ctype=text/css')

  if (wgNamespaceNumber==0 || wgNamespaceNumber==100){
    addOnloadHook(LinkFA)
    importMW('Osm')
    importMW('Collapserefs')
    if (wgArticleId==4401) importMW('Mainpage')
  }else{
    if (wgNamespaceNumber==4){
      if (/^(Мастер статей|Инкубатор)/.test(wgTitle)) importMW('Incubator')
      if (wgTitle=='Скрипты') importMW('Scripts')
    }
    addOnloadHook(icqIcons)
  }

}


if (wgUserGroups){
  for (var i=0; i<wgUserGroups.length; i++) switch (wgUserGroups[i]){
    case 'sysop': importMW('Sysop'); break
 }
 if (wgNamespaceNumber==2 && wgTitle.indexOf(wgUserName)==0 && wgArticleId==0 && /\/skin\.(js|css)$/.test(wgTitle))
   window.location.href = window.location.href.replace(/skin\.(css|js)$/, skin+'.$1')
}


// ВП:СО, кроме статей  В Контакте, Одноклассники и Facebook
if (wgArticleId!=639373 && wgArticleId!=932117 && wgArticleId!=1297302 && wgArticleId!=25133866)
 importMW('Wikibugs')


// iwiki sorting
 if (!wgUserName
     || (wgUserName
         && (((typeof wgLangPrefs == 'undefined') ? false : true)
             || ((typeof wgAddLangHints == 'undefined') ? false : wgAddLangHints)
             || ((typeof wgUseUserLanguage == 'undefined') ? false : wgUseUserLanguage))))
     importMW('Interwiki-links');

var withJS = document.URL.match(/[&?]withjs=((mediawiki:)?([^&#]+))/i)
if (withJS) importScript_('MediaWiki:'+withJS[3])

if (!window.wgUserName) appendCSS('#mw-fr-revisiontag {display:none}')

function addWikifButton() {
        var toolbar = document.getElementById('toolbar')
        if (!toolbar) return
        var i = document.createElement('img')
        i.src = 'http://upload.wikimedia.org/wikisource/ru/d/d1/Button-wikifikator.png'
        i.alt = i.title = 'Wikifikátor'
        i.onclick = Wikify
        i.style.cursor = 'pointer'
        toolbar.appendChild(i)
}
if (document.URL.indexOf('action=edit') > 0 || document.URL.indexOf('action=submit') > 0) {
document.write('<script type="text/javascript" src="http://ru.wikipedia.org/w/index.php?title=MediaWiki:Wikificator.js&action=raw&ctype=text/javascript"><\/script>')
        addOnloadHook(addWikifButton)
}

////////////////////////////////////////////////////////////////
// =-=-=- HELPER FUNCTIONS -=-=-=-
function addlilink(tabs, url, name, id, title, key){
    var na = document.createElement('a');
    na.href = url;
    na.appendChild(document.createTextNode(name));
    var li = document.createElement('li');
    if(id) li.id = id;
    li.appendChild(na);
    tabs.appendChild(li);
    if(id)
    {
        if(key && title)
        {
            ta[id] = [key, title];
        }
        else if(key)
        {
            ta[id] = [key, ''];
        }
        else if(title)
        {
            ta[id] = ['', title];
        }
    }
    // re-render the title and accesskeys from existing code in wikibits.js
    akeytt();
    return li;
}

function addToolboxLink(url, name, id, title){
    var tb = document.getElementById('p-tb').getElementsByTagName('ul')[0];
    addlilink(tb, url, name, id, title);
}

function addTab(url, name, id, title, key) {
    return addPortletLink('p-cactions', url, name, id, title, key);
}

function addLink(where, url, name, id, title, key, after){
    var na = document.createElement('a');
    na.href = url;
    na.appendChild(document.createTextNode(name));
    var li = document.createElement('li');
    if(id) li.id = id;
    li.appendChild(na);
    var tabs = document.getElementById(where).getElementsByTagName('ul')[0];
    if(after) {
	tabs.insertBefore(li,document.getElementById(after));
    } else {
	tabs.appendChild(li);
    }
    if(id) {
	if(key && title) { ta[id] = [key, title]; }
	else if(key) { ta[id] = [key, '']; }
	else if(title) { ta[id] = ['', title];} 
    }
    // re-render the title and accesskeys from existing code in wikibits.js
    akeytt();
    return li;
}

function addlimenu(tabs, name, id)
{
    var na = document.createElement('a');
    na.href = '#';
    var mn = document.createElement('ul');
    na.appendChild(document.createTextNode(name));
    var li = document.createElement('li');
    li.id = id;
    li.className = 'tabmenu';
    li.appendChild(na);
    li.appendChild(mn);
    tabs.appendChild(li);
    return li;
}

function addnavbox_link(URL,Name,ID)
{
var portlet = document.getElementById('p-navigation');
var links = portlet.getElementsByTagName('ul')[0];
links.innerHTML += '<li id="' + ID + '"><a href="' + URL + '">' + Name + '</a></li>';
}

/*
////////////////////////////////////////////////////////////////
// =-=-=- HELPER FUNCTIONS -=-=-=-
function addlilink(tabs, url, name, id, title, key){
    var na = document.createElement('a');
    na.href = url;
    na.appendChild(document.createTextNode(name));
    var li = document.createElement('li');
    if(id) li.id = id;
    li.appendChild(na);
    tabs.appendChild(li);
    if(id)
    {
        if(key && title)
        {
            ta[id] = [key, title];
        }
        else if(key)
        {
            ta[id] = [key, ''];
        }
        else if(title)
        {
            ta[id] = ['', title];
        }
    }
    // re-render the title and accesskeys from existing code in wikibits.js
    akeytt();
    return li;
}

function addToolboxLink(url, name, id, title){
    var tb = document.getElementById('p-tb').getElementsByTagName('ul')[0];
    addlilink(tb, url, name, id, title);
}

function addTab(url, name, id, title, key) {
    return addPortletLink('p-cactions', url, name, id, title, key);
}

function addLink(where, url, name, id, title, key, after){
    var na = document.createElement('a');
    na.href = url;
    na.appendChild(document.createTextNode(name));
    var li = document.createElement('li');
    if(id) li.id = id;
    li.appendChild(na);
    var tabs = document.getElementById(where).getElementsByTagName('ul')[0];
    if(after) {
	tabs.insertBefore(li,document.getElementById(after));
    } else {
	tabs.appendChild(li);
    }
    if(id) {
	if(key && title) { ta[id] = [key, title]; }
	else if(key) { ta[id] = [key, '']; }
	else if(title) { ta[id] = ['', title];} 
    }
    // re-render the title and accesskeys from existing code in wikibits.js
    akeytt();
    return li;
}

function addlimenu(tabs, name, id)
{
    var na = document.createElement('a');
    na.href = '#';
    var mn = document.createElement('ul');
    na.appendChild(document.createTextNode(name));
    var li = document.createElement('li');
    li.id = id;
    li.className = 'tabmenu';
    li.appendChild(na);
    li.appendChild(mn);
    tabs.appendChild(li);
    return li;
}

function addnavbox_link(URL,Name,ID)
{
var portlet = document.getElementById('p-navigation');
var links = portlet.getElementsByTagName('ul')[0];
links.innerHTML += '<li id="' + ID + '"><a href="' + URL + '">' + Name + '</a></li>';
}
/////////////////////////////////////////////
*/
document.write("<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js' type='text/javascript'></script>");

document.write("<script src='/index.php?title=Global.js&action=raw&smaxage=0&ctype=text/javascript' type='text/javascript'></script>")


--------------------------------------------------------------------------------------------

/**
 * TableSorter for MediaWiki
 *
 * Written 2011 Leo Koppelkamm
 * Based on tablesorter.com plugin, written (c) 2007 Christian Bach.
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * @depends on mw.config (wgDigitTransformTable, wgMonthNames, wgMonthNamesShort,
 * wgDefaultDateFormat, wgContentLanguage)
 */
/**
 *
 * @description Create a sortable table with multi-column sorting capabilitys
 *
 * @example $( 'table' ).tablesorter();
 * @desc Create a simple tablesorter interface.
 *
 * @option String cssHeader ( optional ) A string of the class name to be appended
 *         to sortable tr elements in the thead of the table. Default value:
 *         "header"
 *
 * @option String cssAsc ( optional ) A string of the class name to be appended to
 *         sortable tr elements in the thead on a ascending sort. Default value:
 *         "headerSortUp"
 *
 * @option String cssDesc ( optional ) A string of the class name to be appended
 *         to sortable tr elements in the thead on a descending sort. Default
 *         value: "headerSortDown"
 *
 * @option String sortInitialOrder ( optional ) A string of the inital sorting
 *         order can be asc or desc. Default value: "asc"
 *
 * @option String sortMultisortKey ( optional ) A string of the multi-column sort
 *         key. Default value: "shiftKey"
 *
 * @option Boolean sortLocaleCompare ( optional ) Boolean flag indicating whatever
 *         to use String.localeCampare method or not. Set to false.
 *
 * @option Boolean cancelSelection ( optional ) Boolean flag indicating if
 *         tablesorter should cancel selection of the table headers text.
 *         Default value: true
 *
 * @option Boolean debug ( optional ) Boolean flag indicating if tablesorter
 *         should display debuging information usefull for development.
 *
 * @type jQuery
 *
 * @name tablesorter
 *
 * @cat Plugins/Tablesorter
 *
 * @author Christian Bach/christian.bach@polyester.se
 */

( function( $ ) {

	/* Local scope */

	var	ts,
		parsers = [];

	/* Parser utility functions */

	function getParserById( name ) {
		var len = parsers.length;
		for ( var i = 0; i < len; i++ ) {
			if ( parsers[i].id.toLowerCase() === name.toLowerCase() ) {
				return parsers[i];
			}
		}
		return false;
	}

	function getElementText( node ) {
		var $node = $( node ),
			data = $node.attr( 'data-sort-value' );
		if ( data !== undefined ) {
			return data;
		} else {
			return $node.text();
		}
	}

	function getTextFromRowAndCellIndex( rows, rowIndex, cellIndex ) {
		if ( rows[rowIndex] && rows[rowIndex].cells[cellIndex] ) {
			return $.trim( getElementText( rows[rowIndex].cells[cellIndex] ) );
		} else {
			return '';
		}
	}

	function detectParserForColumn( table, rows, cellIndex ) {
		var	l = parsers.length,
			nodeValue,
			// Start with 1 because 0 is the fallback parser
			i = 1,
			rowIndex = 0,
			concurrent = 0,
			needed = ( rows.length > 4 ) ? 5 : rows.length;

		while( i < l ) {
			nodeValue = getTextFromRowAndCellIndex( rows, rowIndex, cellIndex );
			if ( nodeValue !== '') {
				if ( parsers[i].is( nodeValue, table ) ) {
					concurrent++;
					rowIndex++;
					if ( concurrent >= needed ) {
						// Confirmed the parser for multiple cells, let's return it
						return parsers[i];
					}
				} else {
					// Check next parser, reset rows
					i++;
					rowIndex = 0;
					concurrent = 0;
				}
			} else {
				// Empty cell
				rowIndex++;
				if ( rowIndex > rows.length ) {
					rowIndex = 0;
					i++;
				}
			}
		}

		// 0 is always the generic parser (text)
		return parsers[0];
	}

	function buildParserCache( table, $headers ) {
		var	rows = table.tBodies[0].rows,
			sortType,
			parsers = [];

		if ( rows[0] ) {

			var	cells = rows[0].cells,
				len = cells.length,
				i, parser;

			for ( i = 0; i < len; i++ ) {
				parser = false;
				sortType = $headers.eq( i ).data( 'sort-type' );
				if ( sortType !== undefined ) {
					parser = getParserById( sortType );
				}

				if ( parser === false ) {
					parser = detectParserForColumn( table, rows, i );
				}

				parsers.push( parser );
			}
		}
		return parsers;
	}

	/* Other utility functions */

	function buildCache( table ) {
		var	totalRows = ( table.tBodies[0] && table.tBodies[0].rows.length ) || 0,
			totalCells = ( table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length ) || 0,
			parsers = table.config.parsers,
			cache = {
				row: [],
				normalized: []
			};

		for ( var i = 0; i < totalRows; ++i ) {

			// Add the table data to main data array
			var	$row = $( table.tBodies[0].rows[i] ),
				cols = [];

			// if this is a child row, add it to the last row's children and
			// continue to the next row
			if ( $row.hasClass( table.config.cssChildRow ) ) {
				cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add( $row );
				// go to the next for loop
				continue;
			}

			cache.row.push( $row );

			for ( var j = 0; j < totalCells; ++j ) {
				cols.push( parsers[j].format( getElementText( $row[0].cells[j] ), table, $row[0].cells[j] ) );
			}

			cols.push( cache.normalized.length ); // add position for rowCache
			cache.normalized.push( cols );
			cols = null;
		}

		return cache;
	}

	function appendToTable( table, cache ) {
		var	row = cache.row,
			normalized = cache.normalized,
			totalRows = normalized.length,
			checkCell = ( normalized[0].length - 1 ),
			fragment = document.createDocumentFragment();

		for ( var i = 0; i < totalRows; i++ ) {
			var pos = normalized[i][checkCell];

			var l = row[pos].length;

			for ( var j = 0; j < l; j++ ) {
				fragment.appendChild( row[pos][j] );
			}

		}
		table.tBodies[0].appendChild( fragment );
	}
	
	/**
	 * Find all header rows in a thead-less table and put them in a <thead> tag.
	 * This only treats a row as a header row if it contains only <th>s (no <td>s)
	 * and if it is preceded entirely by header rows. The algorithm stops when
	 * it encounters the first non-header row.
	 * 
	 * After this, it will look at all rows at the bottom for footer rows
	 * And place these in a tfoot using similar rules.
	 * @param $table jQuery object for a <table>
	 */ 
	function emulateTHeadAndFoot( $table ) {
		var $rows = $table.find( '> tbody > tr' );
		if( !$table.get(0).tHead ) {
			var $thead = $( '<thead>' );
			$rows.each( function() {
				if ( $(this).children( 'td' ).length > 0 ) {
					// This row contains a <td>, so it's not a header row
					// Stop here
					return false;
				}
				$thead.append( this );
			} );
			$table.prepend( $thead );
		}
		if( !$table.get(0).tFoot ) {
			var $tfoot = $( '<tfoot>' );
			var len = $rows.length;
			for ( var i = len-1; i >= 0; i-- ) {
				if( $( $rows[i] ).children( 'td' ).length > 0 ){
					break;
				}
				$tfoot.prepend( $( $rows[i] ));
			} 
			$table.append( $tfoot );
		}
	}

	function buildHeaders( table, msg ) {
		var	maxSeen = 0,
			longest,
			realCellIndex = 0,
			$tableHeaders = $( 'thead:eq(0) tr', table );
		if ( $tableHeaders.length > 1 ) {
			$tableHeaders.each(function() {
				if ( this.cells.length > maxSeen ) {
					maxSeen = this.cells.length;
					longest = this;
				}
			});
			$tableHeaders = $( longest );
		}
		$tableHeaders = $tableHeaders.children( 'th' ).each( function( index ) {
			this.column = realCellIndex;

			var colspan = this.colspan;
			colspan = colspan ? parseInt( colspan, 10 ) : 1;
			realCellIndex += colspan;

			this.order = 0;
			this.count = 0;

			if ( $( this ).is( '.unsortable' ) ) {
				this.sortDisabled = true;
			}

			if ( !this.sortDisabled ) {
				var $th = $( this ).addClass( table.config.cssHeader ).attr( 'title', msg[1] );
			}

			// add cell to headerList
			table.config.headerList[index] = this;
		} );

		return $tableHeaders;

	}

	function isValueInArray( v, a ) {
		var l = a.length;
		for ( var i = 0; i < l; i++ ) {
			if ( a[i][0] == v ) {
				return true;
			}
		}
		return false;
	}

	function setHeadersCss( table, $headers, list, css, msg ) {
		// Remove all header information
		$headers.removeClass( css[0] ).removeClass( css[1] );

		var h = [];
		$headers.each( function( offset ) {
			if ( !this.sortDisabled ) {
				h[this.column] = $( this );
			}
		} );

		var l = list.length;
		for ( var i = 0; i < l; i++ ) {
			h[ list[i][0] ].addClass( css[ list[i][1] ] ).attr( 'title', msg[ list[i][1] ] );
		}
	}

	function sortText( a, b ) {
		return ( (a < b) ? false : ((a > b) ? true : 0) );
	}

	function sortTextDesc( a, b ) {
		return ( (b < a) ? false : ((b > a) ? true : 0) );
	}

	function checkSorting( array1, array2, sortList ) {
		var col, fn, ret;
		for ( var i = 0, len = sortList.length; i < len; i++ ) {
			col = sortList[i][0];
			fn = ( sortList[i][1] ) ? sortTextDesc : sortText;
			ret = fn.call( this, array1[col], array2[col] );
			if ( ret !== 0 ) {
				return ret;
			}
		}
		return ret;
	}

	// Merge sort algorithm
	// Based on http://en.literateprograms.org/Merge_sort_(JavaScript)
	function mergeSortHelper( array, begin, beginRight, end, sortList ) {
		for ( ; begin < beginRight; ++begin ) {
			if ( checkSorting( array[begin], array[beginRight], sortList ) ) {
				var v = array[begin];
				array[begin] = array[beginRight];
				var begin2 = beginRight;
				while ( begin2 + 1 < end && checkSorting( v, array[begin2 + 1], sortList ) ) {
					var tmp = array[begin2];
					array[begin2] = array[begin2 + 1];
					array[begin2 + 1] = tmp;
					++begin2;
				}
				array[begin2] = v;
			}
		}
	}

	function mergeSort(array, begin, end, sortList) {
		var size = end - begin;
		if ( size < 2 ) {
			return;
		}

		var beginRight = begin + Math.floor(size / 2);

		mergeSort( array, begin, beginRight, sortList );
		mergeSort( array, beginRight, end, sortList );
		mergeSortHelper( array, begin, beginRight, end, sortList );
	}

	function multisort( table, sortList, cache ) {
		var i = sortList.length;
		mergeSort( cache.normalized, 0, cache.normalized.length, sortList );

		return cache;
	}

	function buildTransformTable() {
		var digits = '0123456789,.'.split( '' );
		var separatorTransformTable = mw.config.get( 'wgSeparatorTransformTable' );
		var digitTransformTable = mw.config.get( 'wgDigitTransformTable' );
		if ( separatorTransformTable === null || ( separatorTransformTable[0] === '' && digitTransformTable[2] === '' ) ) {
			ts.transformTable = false;
		} else {
			ts.transformTable = {};

			// Unpack the transform table
			var ascii = separatorTransformTable[0].split( "\t" ).concat( digitTransformTable[0].split( "\t" ) );
			var localised = separatorTransformTable[1].split( "\t" ).concat( digitTransformTable[1].split( "\t" ) );

			// Construct regex for number identification
			for ( var i = 0; i < ascii.length; i++ ) {
				ts.transformTable[localised[i]] = ascii[i];
				digits.push( $.escapeRE( localised[i] ) );
			}
		}
		var digitClass = '[' + digits.join( '', digits ) + ']';

		// We allow a trailing percent sign, which we just strip. This works fine
		// if percents and regular numbers aren't being mixed.
		ts.numberRegex = new RegExp("^(" + "[-+\u2212]?[0-9][0-9,]*(\\.[0-9,]*)?(E[-+\u2212]?[0-9][0-9,]*)?" + // Fortran-style scientific
		"|" + "[-+\u2212]?" + digitClass + "+[\\s\\xa0]*%?" + // Generic localised
		")$", "i");
	}

	function buildDateTable() {
		var regex = [];
		ts.monthNames = [
			[],
			[]
		];

		for ( var i = 1; i < 13; i++ ) {
			ts.monthNames[0][i] = mw.config.get( 'wgMonthNames' )[i].toLowerCase();
			ts.monthNames[1][i] = mw.config.get( 'wgMonthNamesShort' )[i].toLowerCase().replace( '.', '' );
			regex.push( $.escapeRE( ts.monthNames[0][i] ) );
			regex.push( $.escapeRE( ts.monthNames[1][i] ) );
		}

		// Build piped string
		regex = regex.join( '|' );

		// Build RegEx
		// Any date formated with . , ' - or /
		ts.dateRegex[0] = new RegExp( /^\s*\d{1,2}[\,\.\-\/'\s]{1,2}\d{1,2}[\,\.\-\/'\s]{1,2}\d{2,4}\s*?/i);

		// Written Month name, dmy
		ts.dateRegex[1] = new RegExp( '^\\s*\\d{1,2}[\\,\\.\\-\\/\'\\s]*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i' );

		// Written Month name, mdy
		ts.dateRegex[2] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]*\\d{1,2}[\\,\\.\\-\\/\'\\s]*\\d{2,4}\\s*$', 'i' );

	}

	function explodeRowspans( $table ) {
		// Split multi row cells into multiple cells with the same content
		$table.find( '> tbody > tr > [rowspan]' ).each(function() {
			var rowSpan = this.rowSpan;
			this.rowSpan = 1;
			var cell = $( this );
			var next = cell.parent().nextAll();
			for ( var i = 0; i < rowSpan - 1; i++ ) {
				var td = next.eq( i ).children( 'td' );
				if ( !td.length ) {
					next.eq( i ).append( cell.clone() );
				} else if ( this.cellIndex === 0 ) {
					td.eq( this.cellIndex ).before( cell.clone() );
				} else {
					td.eq( this.cellIndex - 1 ).after( cell.clone() );
				}
			}
		});
	}

	function buildCollationTable() {
		ts.collationTable = mw.config.get( 'tableSorterCollation' );
		ts.collationRegex = null;
		if ( ts.collationTable ) {
			var keys = [];

			// Build array of key names
			for ( var key in ts.collationTable ) {
				if ( ts.collationTable.hasOwnProperty(key) ) { //to be safe
					keys.push(key);
				}
			}
			if (keys.length) {
				ts.collationRegex = new RegExp( '[' + keys.join( '' ) + ']', 'ig' );
			}
		}
	}

	function cacheRegexs() {
		if ( ts.rgx ) {
			return;
		}
		ts.rgx = {
			IPAddress: [
				new RegExp( /^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/)
			],
			currency: [
				new RegExp( /^[£$€?.]/),
				new RegExp( /[£$€]/g)
			],
			url: [
				new RegExp( /^(https?|ftp|file):\/\/$/),
				new RegExp( /(https?|ftp|file):\/\//)
			],
			isoDate: [
				new RegExp( /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/)
			],
			usLongDate: [
				new RegExp( /^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/)
			],
			time: [
				new RegExp( /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/)
			]
		};
	}

	/* Public scope */

	$.tablesorter = {

			defaultOptions: {
				cssHeader: 'headerSort',
				cssAsc: 'headerSortUp',
				cssDesc: 'headerSortDown',
				cssChildRow: 'expand-child',
				sortInitialOrder: 'asc',
				sortMultiSortKey: 'shiftKey',
				sortLocaleCompare: false,
				parsers: {},
				widgets: [],
				headers: {},
				cancelSelection: true,
				sortList: [],
				headerList: [],
				selectorHeaders: 'thead tr:eq(0) th',
				debug: false
			},

			dateRegex: [],
			monthNames: [],

			/**
			 * @param $tables {jQuery}
			 * @param settings {Object} (optional)
			 */
			construct: function( $tables, settings ) {
				return $tables.each( function( i, table ) {
					// Declare and cache.
					var	$document, $headers, cache, config, sortOrder,
						$table = $( table ),
						shiftDown = 0,
						firstTime = true;

					// Quit if no tbody
					if ( !table.tBodies ) {
						return;
					}
					if ( !table.tHead ) {
						// No thead found. Look for rows with <th>s and
						// move them into a <thead> tag or a <tfoot> tag
						emulateTHeadAndFoot( $table );
						
						// Still no thead? Then quit
						if ( !table.tHead ) {
							return;
						}
					}
					$table.addClass( "jquery-tablesorter" );

					// New config object.
					table.config = {};

					// Merge and extend.
					config = $.extend( table.config, $.tablesorter.defaultOptions, settings );

					// Save the settings where they read
					$.data( table, 'tablesorter', config );

					// Get the CSS class names, could be done else where.
					var sortCSS = [ config.cssDesc, config.cssAsc ];
					var sortMsg = [ mw.msg( 'sort-descending' ), mw.msg( 'sort-ascending' ) ];

					// Build headers
					$headers = buildHeaders( table, sortMsg );

					// Grab and process locale settings
					buildTransformTable();
					buildDateTable();
					buildCollationTable();

					// Precaching regexps can bring 10 fold
					// performance improvements in some browsers.
					cacheRegexs();

					// Apply event handling to headers
					// this is too big, perhaps break it out?
					$headers.click( function( e ) {
						if ( e.target.nodeName.toLowerCase() == 'a' ) {
							// The user clicked on a link inside a table header
							// Do nothing and let the default link click action continue
							return true;
						}

						if ( firstTime ) {
							firstTime = false;
							
							// Legacy fix of .sortbottoms
							// Wrap them inside inside a tfoot (because that's what they actually want to be) &
							// and put the <tfoot> at the end of the <table>
							var $sortbottoms = $table.find( '> tbody > tr.sortbottom' );
							if ( $sortbottoms.length ) {
								var $tfoot = $table.children( 'tfoot' );
								if ( $tfoot.length ) {
									$tfoot.eq(0).prepend( $sortbottoms );
								} else {
									$table.append( $( '<tfoot>' ).append( $sortbottoms ) )
								}
							}
							
							explodeRowspans( $table );
							// try to auto detect column type, and store in tables config
							table.config.parsers = buildParserCache( table, $headers );
							// build the cache for the tbody cells
							cache = buildCache( table );
						}
						var totalRows = ( $table[0].tBodies[0] && $table[0].tBodies[0].rows.length ) || 0;
						if ( !table.sortDisabled && totalRows > 0 ) {

							// Cache jQuery object
							var $cell = $( this );

							// Get current column index
							var i = this.column;

							// Get current column sort order
							this.order = this.count % 2;
							this.count++;

							// User only wants to sort on one column
							if ( !e[config.sortMultiSortKey] ) {
								// Flush the sort list
								config.sortList = [];
								// Add column to sort list
								config.sortList.push( [i, this.order] );

							// Multi column sorting
							} else {
								// The user has clicked on an already sorted column.
								if ( isValueInArray( i, config.sortList ) ) {
									// Reverse the sorting direction for all tables.
									for ( var j = 0; j < config.sortList.length; j++ ) {
										var s = config.sortList[j],
											o = config.headerList[s[0]];
										if ( s[0] == i ) {
											o.count = s[1];
											o.count++;
											s[1] = o.count % 2;
										}
									}
								} else {
									// Add column to sort list array
									config.sortList.push( [i, this.order] );
								}
							}

							// Set CSS for headers
							setHeadersCss( $table[0], $headers, config.sortList, sortCSS, sortMsg );
							appendToTable(
								$table[0], multisort( $table[0], config.sortList, cache )
							);

							// Stop normal event by returning false
							return false;
						}

					// Cancel selection
					} ).mousedown( function() {
						if ( config.cancelSelection ) {
							this.onselectstart = function() {
								return false;
							};
							return false;
						}
					} );
				} );
			},

			addParser: function( parser ) {
				var	l = parsers.length,
					a = true;
				for ( var i = 0; i < l; i++ ) {
					if ( parsers[i].id.toLowerCase() == parser.id.toLowerCase() ) {
						a = false;
					}
				}
				if ( a ) {
					parsers.push( parser );
				}
			},

			formatDigit: function( s ) {
				if ( ts.transformTable !== false ) {
					var	out = '',
						c;
					for ( var p = 0; p < s.length; p++ ) {
						c = s.charAt(p);
						if ( c in ts.transformTable ) {
							out += ts.transformTable[c];
						} else {
							out += c;
						}
					}
					s = out;
				}
				var i = parseFloat( s.replace( /[, ]/g, '' ).replace( "\u2212", '-' ) );
				return ( isNaN(i)) ? 0 : i;
			},

			formatFloat: function( s ) {
				var i = parseFloat(s);
				return ( isNaN(i)) ? 0 : i;
			},

			formatInt: function( s ) {
				var i = parseInt( s, 10 );
				return ( isNaN(i)) ? 0 : i;
			},

			clearTableBody: function( table ) {
				if ( $.browser.msie ) {
					var empty = function( el ) {
						while ( el.firstChild ) {
							el.removeChild( el.firstChild );
						}
					};
					empty( table.tBodies[0] );
				} else {
					table.tBodies[0].innerHTML = '';
				}
			}
		};

	// Shortcut
	ts = $.tablesorter;

	// Register as jQuery prototype method
	$.fn.tablesorter = function( settings ) {
		return ts.construct( this, settings );
	};

	// Add default parsers
	ts.addParser( {
		id: 'text',
		is: function( s ) {
			return true;
		},
		format: function( s ) {
			s = $.trim( s.toLowerCase() );
			if ( ts.collationRegex ) {
				var tsc = ts.collationTable;
				s = s.replace( ts.collationRegex, function( match ) {
					var r = tsc[match] ? tsc[match] : tsc[match.toUpperCase()];
					return r.toLowerCase();
				} );
			}
			return s;
		},
		type: 'text'
	} );

	ts.addParser( {
		id: 'IPAddress',
		is: function( s ) {
			return ts.rgx.IPAddress[0].test(s);
		},
		format: function( s ) {
			var	a = s.split( '.' ),
				r = '',
				l = a.length;
			for ( var i = 0; i < l; i++ ) {
				var item = a[i];
				if ( item.length == 1 ) {
					r += '00' + item;
				} else if ( item.length == 2 ) {
					r += '0' + item;
				} else {
					r += item;
				}
			}
			return $.tablesorter.formatFloat(r);
		},
		type: 'numeric'
	} );

	ts.addParser( {
		id: 'currency',
		is: function( s ) {
			return ts.rgx.currency[0].test(s);
		},
		format: function( s ) {
			return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[1], '' ) );
		},
		type: 'numeric'
	} );

	ts.addParser( {
		id: 'url',
		is: function( s ) {
			return ts.rgx.url[0].test(s);
		},
		format: function( s ) {
			return $.trim( s.replace( ts.rgx.url[1], '' ) );
		},
		type: 'text'
	} );

	ts.addParser( {
		id: 'isoDate',
		is: function( s ) {
			return ts.rgx.isoDate[0].test(s);
		},
		format: function( s ) {
			return $.tablesorter.formatFloat((s !== '') ? new Date(s.replace(
			new RegExp( /-/g), '/')).getTime() : '0' );
		},
		type: 'numeric'
	} );

	ts.addParser( {
		id: 'usLongDate',
		is: function( s ) {
			return ts.rgx.usLongDate[0].test(s);
		},
		format: function( s ) {
			return $.tablesorter.formatFloat( new Date(s).getTime() );
		},
		type: 'numeric'
	} );

	ts.addParser( {
		id: 'date',
		is: function( s ) {
			return ( ts.dateRegex[0].test(s) || ts.dateRegex[1].test(s) || ts.dateRegex[2].test(s ));
		},
		format: function( s, table ) {
			s = $.trim( s.toLowerCase() );

			for ( var i = 1, j = 0; i < 13 && j < 2; i++ ) {
				s = s.replace( ts.monthNames[j][i], i );
				if ( i == 12 ) {
					j++;
					i = 0;
				}
			}

			s = s.replace( /[\-\.\,' ]/g, '/' );

			// Replace double slashes
			s = s.replace( /\/\//g, '/' );
			s = s.replace( /\/\//g, '/' );
			s = s.split( '/' );

			// Pad Month and Day
			if ( s[0] && s[0].length == 1 ) {
				s[0] = '0' + s[0];
			}
			if ( s[1] && s[1].length == 1 ) {
				s[1] = '0' + s[1];
			}
			var y;

			if ( !s[2] ) {
				// Fix yearless dates
				s[2] = 2000;
			} else if ( ( y = parseInt( s[2], 10) ) < 100 ) {
				// Guestimate years without centuries
				if ( y < 30 ) {
					s[2] = 2000 + y;
				} else {
					s[2] = 1900 + y;
				}
			}
			// Resort array depending on preferences
			if ( mw.config.get( 'wgDefaultDateFormat' ) == 'mdy' || mw.config.get( 'wgContentLanguage' ) == 'en' ) {
				s.push( s.shift() );
				s.push( s.shift() );
			} else if ( mw.config.get( 'wgDefaultDateFormat' ) == 'dmy' ) {
				var d = s.shift();
				s.push( s.shift() );
				s.push(d);
			}
			return parseInt( s.join( '' ), 10 );
		},
		type: 'numeric'
	} );

	ts.addParser( {
		id: 'time',
		is: function( s ) {
			return ts.rgx.time[0].test(s);
		},
		format: function( s ) {
			return $.tablesorter.formatFloat( new Date( '2000/01/01 ' + s ).getTime() );
		},
		type: 'numeric'
	} );

	ts.addParser( {
		id: 'number',
		is: function( s, table ) {
			return $.tablesorter.numberRegex.test( $.trim( s ));
		},
		format: function( s ) {
			return $.tablesorter.formatDigit(s);
		},
		type: 'numeric'
	} );

} )( jQuery );
Jó játékot kíván: a Grepolis csapata!