User:PanSola/sortable mod.js

/* * This is a "nightly" version. * For stable version, see MediaWiki:sortable_mod.js */

/* * Table sorting script by Pan Sola * Based on a script by Joost de Valk at http://www.joostdevalk.nl/code/sortable-table/. * Based on a script from http://www.kryogenix.org/code/browser/sorttable/. * Distributed under the MIT license: http://www.kryogenix.org/code/browser/licence.html. *      Copyright (c) 1997-2006 Stuart Langridge, Joost de Valk. * * Modifications (compared to sorttable.js): * * Does not strip tags inside header cells * * Images are sorted (instead of ignored) by their "alt" field. * * Do NOT use this on tables with colspan or rowspan * */

/* document.write(' ');

sorttable.js, modified
* Overwrites the default functions in http://gw.gamewikis.org/skins/common/sorttable.js * * Functions changed: * * ts_makeSortable(table) * * ts_getInnerText(el) * * /*

Primary functions
*/ var image_path = stylepath+"/common/images/"; var image_up = "sort_up.gif"; var image_down = "sort_down.gif"; var image_none = "sort_none.gif"; var europeandate = wgContentLanguage != "en"; // The non-American-inclined can change to "true"

var alternate_row_colors = true;

hookEvent( "load", sortables_init);

var SORT_COLUMN_INDEX; var thead = false;

/*

sortables_init
*/ function sortables_init { var idnum = 0; // Find all tables with class sortable and make them sortable if (!document.getElementsByTagName) return; tbls = document.getElementsByTagName("table"); for (ti=0;ti 0) { if (table.tHead && table.tHead.rows.length > 0) { var firstRow = table.tHead.rows[table.tHead.rows.length-1]; thead = true; } else { var firstRow = table.rows[0]; }	}	if (!firstRow) return;

// We have a first row: assume it's the header, and make its contents clickable links for (var i=0;i  '; }	}	if (alternate_row_colors) { alternate(table); } } /*

ts_getInnerText(el)
*/ function ts_getInnerText(el) { if (typeof el == "string") return el; if (typeof el == "undefined") { return el }; if (el.innerText) return el.innerText;	//Not needed but it is faster var str = ""; var cs = el.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { switch (cs[i].nodeName) { case "IMG": // IMAGE_NODE str += cs[i].alt; break; case "#text":	//TEXT_NODE str += cs[i].nodeValue; break; default: //ELEMENT_NODE str += ts_getInnerText(cs[i]); }	}	return str; } /*

colSortInit(td)
*/ function colSortInit(th){ var sortType = th.getAttribute("sortType"); if (!sortType){

var column = td.cellIndex; var table = getParent(th,'TABLE'); for( var i = 1, itm = ""; itm.match(/^([\s]|\n|\ |)*$/) && i < table.tBodies[0].rows.length ; i++) { var itm = ts_getInnerText(table.tBodies[0].rows[i].cells[column]); itm = trim(itm); itm = itm.replace(/¼/, ".25").replace(/½/, ".5").replace(/¾/, ".75"); }

if (itm == "") { sortType = "noSort"; th.setAttribute("isKeyed", true); return; }

sortType = "caseinsensitive"; if (itm.match(/^[\d.,]+\%?/)) sortType = "numeric_with_units"; if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/)) sortType = "date"; if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/)) sortType = "date"; if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/)) sortType = "date"; if (itm.match(/^[£$€Û¢´]/)) sortType = "currency"; if (itm.match(/^[\d.,]+\%?$/)) sortType = "numeric"; th.setAttribute("sortType", sortType); }

switch (sortType){ 'caseinsensitive': keyfn = key_caseinsensitive; break; 'numeric_with_units': keyfn = key_numeric-unit; break; 'date': keyfn = key_date; break; 'currency': keyfn = key_unit-numeric; break; 'numeric': keyfn = key_numeric; break; default: keyfn = key_caseinsensitive; }	for( var i = 1; i < table.tBodies[0].rows.length ; i++) { var myCell = table.tBodies[0].rows[i].cells[column]; var itm = ts_getInnerText(myCell); itm = trim(itm); itm = itm.replace(/¼/, ".25").replace(/½/, ".5").replace(/¾/, ".75"); myCell.setAttribute("sortKey", sortfn(itm)); }	th.setAttribute("isKeyed", true); return sortType; } /*

ts_resortTable(lnk)
*/ function ts_resortTable(lnk) {

/* Begin Dead code */ // get the span var span; for (var ci=0;ci<lnk.childNodes.length;ci++) { if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase == 'span') span = lnk.childNodes[ci]; }	var spantext = ts_getInnerText(span); /* End Dead code */

var th = lnk.parentNode; var column = th.cellIndex; var table = getParent(td,'TABLE');

// Work out a type for the column if (table.rows.length <= 1) return;

var sortType = td.getAttribute("isKeyed"); if (!isKeyed) { colSortInit(th); }	sortType = td.getAttribute("sortType");

debug(sortType + ' ');

switch (sortType){ 'numeric_with_units': 'currency': sortfn = ts_sort_multi; break; 'caseinsensitive': 'date': 'numeric': sortfn = ts_sort_single; break; default: sortfn = ts_sort_default; }

SORT_COLUMN_INDEX = column; var firstRow = new Array; var newRows = new Array;

for (k=0;k<table.tBodies.length;k++) { for (i=0;i<table.tBodies[k].rows[0].length;i++) { firstRow[i] = table.tBodies[k].rows[0][i]; }	}

for (k=0;k'; newRows.reverse; span.setAttribute('sortdir','up'); } else { ARROW = ''; span.setAttribute('sortdir','down'); } 	// We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones // don't do sortbottom rows for (i=0; i<newRows.length; i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) { table.tBodies[0].appendChild(newRows[i]); }	}	// do sortbottom rows only for (i=0; i<newRows.length; i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]); }

// Delete any other arrows there may be showing var allspans = document.getElementsByTagName("span"); for (var ci=0;ci'; }		}	}

span.innerHTML = ARROW; alternate(table); printDebug; } /*

getParent(el, pTagName)
*/ function getParent(el, pTagName) { if (el == null) { return null; } else if (el.nodeType == 1 && el.tagName.toLowerCase == pTagName.toLowerCase) {	// Gecko bug, supposed to be uppercase return el; } else { return getParent(el.parentNode, pTagName); } } /*

Sorting functions
*/ /*

ts_sort_single(a,b)
*/ function ts_sort_single(a,b) { aa = a.cells[SORT_COLUMN_INDEX].getAttribute('sortKey'); aa = b.cells[SORT_COLUMN_INDEX].getAttribute('sortKey');

if (aa==bb) { return 0; }	if (aa<bb) { return -1; }	return 1; } /*

ts_sort_multi(a,b)
*/ function ts_sort_multi(a,b) { aa = a.cells[SORT_COLUMN_INDEX].getAttribute('sortKey'); bb = b.cells[SORT_COLUMN_INDEX].getAttribute('sortKey');

for (var i=0; i < aa.length; i++){ if (aa[i] == bb[i]) continue; if (aa[i] < bb[i]) return -1; return 1; } } /*

ts_sort_default(a,b)
*/ function ts_sort_default(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa==bb) { return 0; }	if (aa<bb) { return -1; }	return 1; } /*

"Library" functions
*/ /*

addEvent(elm, evType, fn, useCapture)
*/ function addEvent(elm, evType, fn, useCapture) // addEvent and removeEvent // cross-browser event handling for IE5+,	NS6 and Mozilla // By Scott Andrew {	if (elm.addEventListener){ elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent){ var r = elm.attachEvent("on"+evType, fn); return r;	} else { alert("Handler could not be removed"); } } /*

replace(s, t, u)
*/ function replace(s, t, u) { /*	** Replace a token in a string **   s  string to be processed **   t  token to be found and removed **   u  token to be inserted ** returns new String */	i = s.indexOf(t); r = ""; if (i == -1) return s;	r += s.substring(0,i) + u;	if ( i + t.length < s.length) { r += replace(s.substring(i + t.length, s.length), t, u); }	return r; } /*

trim(s)
*/ function trim(s) { return s.replace(/^([ \t]|\n|\ |)*/, "").replace(/([ \t]|\n|\ |)*$/, ""); } /*

alternate(table)
*/ function alternate(table) { // Take object table and get all it's tbodies. var tableBodies = table.getElementsByTagName("tbody"); // Loop through these tbodies for (var i = 0; i < tableBodies.length; i++) { // Take the tbody, and get all it's rows var tableRows = tableBodies[i].getElementsByTagName("tr"); // Loop through these rows // Start at 1 because we want to leave the heading row untouched for (var j = 0; j < tableRows.length; j++) { // Check if j is even, and apply classes for both possible results if ( (j % 2) == 0 ) { if ( !(tableRows[j].className.indexOf('odd') == -1) ) { tableRows[j].className = replace(tableRows[j].className, 'odd', 'even'); } else { if ( tableRows[j].className.indexOf('even') == -1 ) { tableRows[j].className += " even"; }				}			} else { if ( !(tableRows[j].className.indexOf('even') == -1) ) { tableRows[j].className = replace(tableRows[j].className, 'even', 'odd'); } else { if ( tableRows[j].className.indexOf('odd') == -1 ) { tableRows[j].className += " odd"; }				}			} 		}	} }

/*

Shaker sort
* */ function shaker_sort(list, comp_func) { // A stable sort function to allow multi-level sorting of data // see: http://en.wikipedia.org/wiki/Cocktail_sort // thanks to Joseph Nahmias var b = 0; var t = list.length - 1; var swap = true;

while(swap) { swap = false; for(var i = b; i < t; ++i) { if ( comp_func(list[i], list[i+1]) > 0 ) { var q = list[i]; list[i] = list[i+1]; list[i+1] = q;               swap = true; }       } // for t--;

if (!swap) break;

for(var i = t; i > b; --i) { if ( comp_func(list[i], list[i-1]) < 0 ) { var q = list[i]; list[i] = list[i-1]; list[i-1] = q;               swap = true; }       } // for b++;

} // while(swap) } /*

Pan Sola's utilities
*/ /*

debug(message)
*/ function debug(message){ debugMSG += message + ' '; }

function printDebug{ var debugDiv = document.getElementById('debugDiv'); debugDiv.innerHTML += debugMSG; debugDiv.style.display = 'block'; debugMSG = ""; }

/* 1.0