Tablesorter demo
All options included, as well as the uitheme widget
by Mottie
HTML
<script src="http://mottie.github.com/tablesorter/js/jquery.tablesorter.js"></script>
<script src="http://mottie.github.com/tablesorter/js/jquery.tablesorter.widgets.js"></script>
<table class="sortable">
<thead>
<tr>
<th class="sorter-false">Region</th>
<th>Salesman</th>
<th>FastCar</th>
<th>RapidZoo</th>
<th>SuperGlue</th>
<th>Grand Total</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="2">Column Totals</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="5">Grand Total</td>
<td></td>
</tr>
</tfoot>
<tbody>
<tr>
<td class="block">Middle</td>
<td>Joseph</td>
<td>$ 3,623</td>
<td>$ 4,782</td>
<td>$ 7,055</td>
<td></td>
</tr>
<tr>
<td class="block">Middle</td>
<td>Lawrence</td>
<td>$ 5,908</td>
<td>$ 4,642</td>
<td>$ 4,593</td>
<td></td>
</tr>
<tr>
<td class="block">Middle</td>
<td>Maria</td>
<td>$ 6,502</td>
<td>$ 3,969</td>
<td>$ 5,408</td>
<td></td>
</tr>
<tr>
<td class="block">Middle</td>
<td>Matt</td>
<td>$ 4,170</td>
<td>$ 6,093</td>
<td>$ 5,039</td>
<td></td>
</tr>
</tbody>
<tbody class="tablesorter-infoOnly">
<tr>
<td colspan="2">Middle Total</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
<tbody>
<tr>
<td class="block">North</td>
<td>Joseph</td>
<td>$ 3,643</td>
<td>$ 5,846</td>
<td>$ 6,574</td>
...
CSS
table.tablesorter {
font-family: arial;
background-color: #cdcdcd;
margin: 10px 0 15px;
font-size: 11px;
width: 100%;
text-align: left;
border-spacing: 0;
}
table.tablesorter, table.tablesorter th, table.tablesorter td {
background-color: #953735;
border: #cdcdcd 1px solid;
color: #fff;
}
table.tablesorter th {
border-collapse: collapse;
font-size: 12px;
padding: 4px;
}
table.tablesorter .header, table.tablesorter .tablesorter-header {
/* white double arrow */
background-image: url(data:image/gif;
base64, R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
background-repeat: no-repeat;
background-position: center right;
padding: 4px 20px 4px 4px;
cursor: pointer;
}
table.tablesorter tbody td {
color: #3d3d3d;
padding: 4px;
background-color: #fff;
vertical-align: top;
}
table.tablesorter th.headerSortUp, table.tablesorter th.tablesorter-headerSortUp {
background-color: #953735;
/* white asc arrow */
background-image: url(data:image/gif;
base64, R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
}
table.tablesorter th.headerSortDown, table.tablesorter th.tablesorter-headerSortDown {
background-color: #953735;
/* white desc arrow */
background-image: url(data:image/gif;
base64, R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
}
/* Zebra Widget - row alternating colors */
table.tablesorter tr.odd td {
background-color: #f0f0f0;
}
table.tablesorter tr.even td {
background-color: #fff;
}
table.tablesorter .tablesorter-infoOnly td, table.tablesorter tr td.block {
background-color: #d99795;
color: #fff;
}
table.tablesorter tfoot td {
background-color: #fff;
color: #000;
}
th.sorter-false {
width: 100px;
}
JavaScript
$(function () {
// http://www.mredkj.com/javascript/nfbasic.html
var addCommas = function (nStr) {
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
},
calculateTotals = function (table) {
var b = table.tBodies,
c = table.config,
skipColumns = 2,
totalColumns = 6,
foot = $(table).find('tfoot td'),
cols = {}, gTotal = 0,
cTotal = [],
bTotal = 0,
rTotal = 0,
k, i, j, r, val;
for (k = 0; k < b.length; k++) {
r = c.cache[k].normalized;
cols[k] = {};
for (i = 0; i < r.length; i++) {
// ignore info rows
if (b[k].className.match(c.cssInfoBlock)) {
continue;
}
rTotal = 0;
// don't include last column in cache because it
// contains the original sort row position
// skip first 2 columns
for (j = skipColumns; j < r[i].length - 1; j++) {
val = typeof r[i][j] === "string" ? parseFloat(r[i][j]) || 0 : r[i][j];
cols[k][j] = (cols[k][j] || 0) + val;
rTotal += val;
cTotal[j] = (cTotal[j] || 0) + val;
}
bTotal += rTotal;
cTotal[j - 1] = (cTotal[j - 1] || 0) + rTotal
b[k]['rows'][i]['cells'][j - 1].innerHTML = '$ ' + addCommas(rTotal);
}
gTotal += bTotal;
if (b[k].className.match(c.cssInfoBlock)) {
// start from 2 to skip "Coumn Totals" spanned cells
for (i = skipColumns; i < totalColumns; i++) {
b[k]['rows'][0]['cells'][i -...