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 -...