/********************************************************************** Table sorting script By Mark Wilton-Jones 01/7/2005 Version 1.0.2 *********************************************************************** Please see http://www.howtocreate.co.uk/jslibs/ for details and a demo of this script Please see http://www.howtocreate.co.uk/jslibs/termsOfUse.html for terms of use Sorts tables (vertically) based on the data they contain. It is able to sort based on either lexical (text) or numeric content. Sorting can be based on the contents of any chosen column, and can use either ascending or descending order. It can be told to ignore heading rows, and rows with specific classes, and can also be told to sort only a specific table body instead of the whole table. Script runs in DOM browsers. To use: Inbetween the <head> tags, put: <script src="PATH TO SCRIPT/tablesort.js" type="text/javascript"></script> The script provides a single function: sortTableRows(tableRef,column,sortType,order,rowsToIgnore[,optional: classPatternToIgnore]) tableRef = node; reference to either a table or tbody element - if tableRef is a table, the first tbody will be sorted (or the whole table if there is no tbody in the source) column = integer; the column to use to determine sort order (starting from 0) sortType = boolean; true = numeric, false = lexical order = boolean; true = smallest first, false = largest first rowsToIgnore = integer; number of initial rows to ignore (for example, heading rows) classPatternToIgnore = optional regular expression; pattern of tr tag class attributes to ignore - null or undefined if none The script will not sort the table if there are less than 2 rows to be sorted. Any rows that are sorted will be put after any rows that are ignored. For example: if( document.getElementById ) { var foo = document.getElementById('mytable'); sortTableRows(foo,3,true,false,2,/\bheadrow\b|\boddrow\b/); } The script does not take rowspan or colspan into account when selecting columns, and will fail with errors if invalid parameters are used. It should be able to cope with (X)HTML within the table cells (sorting will be based on a concatenation of all text nodes). ________________________________________________________________________________*/ function sortTableRows(oTableItem,oColumn,oSortType,oOrder,oIgnoreRows,oIgnoreClass) { if( !document.childNodes || !document.appendChild ) { return; } //prepare the custom sorting function var trimSpace = /^\s+|\s+$/g, oPadding = unescape('%00'); var sortFunc = function (a,b) { var c = totalValueOf(a.quickCells[oColumn]).replace(trimSpace,''); var d = totalValueOf(b.quickCells[oColumn]).replace(trimSpace,''); if( oSortType ) { //numeric sort c = parseFloat(c); d = parseFloat(d); if( isNaN(c) ) { c = oOrder ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; } if( isNaN(d) ) { d = oOrder ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; } //'Infinity - Infinity' is NaN, and IE throws an error return ( c == d ) ? 0 : ( oOrder ? ( c - d ) : ( d - c ) ); } else { //alpha sort while( c.length > d.length ) { d += oPadding; } while( d.length > c.length ) { c += oPadding; } return ( c == d ) ? 0 : ( ( oOrder ? ( d > c ) : ( c > d ) ) ? -1 : 1 ); } }; //prepare the function used to get the text content of the cells - rudimentary, but should hardly be needed var totalValueOf = function (oNode) { var oStr = ''; for( var i = 0, j; i < oNode.childNodes.length; i++ ) { j = oNode.childNodes[i]; if( j.nodeType == 3 ) { oStr += j.nodeValue; } else if( j.nodeType == 1 ) { oStr += totalValueOf( j ); } } return oStr; }; if( oTableItem.tagName.toLowerCase() == 'table' ) { oTableItem = oTableItem.getElementsByTagName('tbody')[0]; //failed to find a table body - do not sort if( !oTableItem ) { return; } } var usableRows = [], actualRows = 0; for( var i = 0, j; i < oTableItem.childNodes.length; i++ ) { j = oTableItem.childNodes[i]; if( j.tagName && j.tagName.toLowerCase() == 'tr' ) { actualRows++; if( ( actualRows > oIgnoreRows ) && ( !oIgnoreClass || !j.className || !j.className.match(oIgnoreClass) ) ) { //we want to sort this row - get accurate refs to the cells (th/td) j.quickCells = []; for( var n = 0, m; n < j.childNodes.length; n++ ) { m = j.childNodes[n]; if( m.tagName && ( m.tagName.toLowerCase() == 'td' || m.tagName.toLowerCase() == 'th' ) ) { j.quickCells[j.quickCells.length] = m; } } usableRows[usableRows.length] = j; } } } if( usableRows.length > 1 ) { //enough rows to sort usableRows.sort(sortFunc); if( window.ActiveXObject && navigator.platform.indexOf('Mac') + 1 && !navigator.__ice_version && ( !window.ScriptEngine || ScriptEngine().indexOf('InScript') == -1 ) && !window.opera ) { //IE Mac will crash - avoid the bug - slower so I will not use this "fix" in browsers that do not need it for( var i = 0; i < usableRows.length; i++ ) { if( usableRows[i] != oTableItem.lastChild ) { oTableItem.insertBefore(usableRows[i],oTableItem.lastChild); oTableItem.insertBefore(oTableItem.lastChild,oTableItem.lastChild.previousSibling); } } } else { for( var i = 0; i < usableRows.length; i++ ) { oTableItem.appendChild(usableRows[i]); } } //fix Opera rendering bug document.body.className = document.body.className; } }