﻿(function($) { $.extend({ tablesorter: new function() { var k = [], widgets = []; this.defaults = { cssHeader: "header", cssAsc: "headerSortUp", cssDesc: "headerSortDown", sortInitialOrder: "asc", sortMultiSortKey: "shiftKey", sortForce: null, sortAppend: null, textExtraction: "simple", parsers: {}, widgets: [], widgetZebra: { css: ["even", "odd"] }, headers: {}, widthFixed: false, cancelSelection: true, sortList: [], headerList: [], dateFormat: "us", decimal: '.', debug: false }; function benchmark(s, d) { log(s + "," + (new Date().getTime() - d.getTime()) + "ms") } this.benchmark = benchmark; function log(s) { if (typeof console != "undefined" && typeof console.debug != "undefined") { console.log(s) } else { alert(s) } } function buildParserCache(a, b) { if (a.config.debug) { var c = "" } var d = a.tBodies[0].rows; if (a.tBodies[0].rows[0]) { var e = [], cells = d[0].cells, l = cells.length; for (var i = 0; i < l; i++) { var p = false; if ($.metadata && ($(b[i]).metadata() && $(b[i]).metadata().sorter)) { p = getParserById($(b[i]).metadata().sorter) } else if ((a.config.headers[i] && a.config.headers[i].sorter)) { p = getParserById(a.config.headers[i].sorter) } if (!p) { p = detectParserForColumn(a, cells[i]) } if (a.config.debug) { c += "column:" + i + " parser:" + p.id + "\n" } e.push(p) } } if (a.config.debug) { log(c) } return e }; function detectParserForColumn(a, b) { var l = k.length; for (var i = 1; i < l; i++) { if (k[i].is($.trim(getElementText(a.config, b)), a, b)) { return k[i] } } return k[0] } function getParserById(a) { var l = k.length; for (var i = 0; i < l; i++) { if (k[i].id.toLowerCase() == a.toLowerCase()) { return k[i] } } return false } function buildCache(a) { if (a.config.debug) { var b = new Date() } var d = (a.tBodies[0] && a.tBodies[0].rows.length) || 0, totalCells = (a.tBodies[0].rows[0] && a.tBodies[0].rows[0].cells.length) || 0, k = a.config.parsers, cache = { row: [], normalized: [] }; for (var i = 0; i < d; ++i) { var c = a.tBodies[0].rows[i], cols = []; cache.row.push($(c)); for (var j = 0; j < totalCells; ++j) { cols.push(k[j].format(getElementText(a.config, c.cells[j]), a, c.cells[j])) } cols.push(i); cache.normalized.push(cols); cols = null }; if (a.config.debug) { benchmark("Building cache for " + d + " rows:", b) } return cache }; function getElementText(a, b) { if (!b) return ""; var t = ""; if (a.textExtraction == "simple") { if (b.childNodes[0] && b.childNodes[0].hasChildNodes()) { t = b.childNodes[0].innerHTML } else { t = b.innerHTML } } else { if (typeof (a.textExtraction) == "function") { t = a.textExtraction(b) } else { t = $(b).text() } } return t } function appendToTable(a, b) { if (a.config.debug) { var d = new Date() } var c = b, r = c.row, n = c.normalized, totalRows = n.length, checkCell = (n[0].length - 1), tableBody = $(a.tBodies[0]), rows = []; for (var i = 0; i < totalRows; i++) { rows.push(r[n[i][checkCell]]); if (!a.config.appender) { var o = r[n[i][checkCell]]; var l = o.length; for (var j = 0; j < l; j++) { tableBody[0].appendChild(o[j]) } } } if (a.config.appender) { a.config.appender(a, rows) } rows = null; if (a.config.debug) { benchmark("Rebuilt table:", d) } applyWidget(a); setTimeout(function() { $(a).trigger("sortEnd") }, 0) }; function buildHeaders(b) { if (b.config.debug) { var c = new Date() } var d = ($.metadata) ? true : false, tableHeadersRows = []; for (var i = 0; i < b.tHead.rows.length; i++) { tableHeadersRows[i] = 0 }; $tableHeaders = $("thead th", b); $tableHeaders.each(function(a) { this.count = 0; this.column = a; this.order = formatSortingOrder(b.config.sortInitialOrder); if (checkHeaderMetadata(this) || checkHeaderOptions(b, a)) this.sortDisabled = true; if (!this.sortDisabled) { $(this).addClass(b.config.cssHeader) } b.config.headerList[a] = this }); if (b.config.debug) { benchmark("Built headers:", c); log($tableHeaders) } return $tableHeaders }; function checkCellColSpan(a, b, d) { var e = [], r = a.tHead.rows, c = r[d].cells; for (var i = 0; i < c.length; i++) { var f = c[i]; if (f.colSpan > 1) { e = e.concat(checkCellColSpan(a, headerArr, d++)) } else { if (a.tHead.length == 1 || (f.rowSpan > 1 || !r[d + 1])) { e.push(f) } } } return e }; function checkHeaderMetadata(a) { if (($.metadata) && ($(a).metadata().sorter === false)) { return true }; return false } function checkHeaderOptions(a, i) { if ((a.config.headers[i]) && (a.config.headers[i].sorter === false)) { return true }; return false } function applyWidget(a) { var c = a.config.widgets; var l = c.length; for (var i = 0; i < l; i++) { getWidgetById(c[i]).format(a) } } function getWidgetById(a) { var l = widgets.length; for (var i = 0; i < l; i++) { if (widgets[i].id.toLowerCase() == a.toLowerCase()) { return widgets[i] } } }; function formatSortingOrder(v) { if (typeof (v) != "Number") { i = (v.toLowerCase() == "desc") ? 1 : 0 } else { i = (v == (0 || 1)) ? v : 0 } return i } 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(b, c, d, e) { c.removeClass(e[0]).removeClass(e[1]); var h = []; c.each(function(a) { if (!this.sortDisabled) { h[this.column] = $(this) } }); var l = d.length; for (var i = 0; i < l; i++) { h[d[i][0]].addClass(e[d[i][1]]) } } function fixColumnWidth(a, b) { var c = a.config; if (c.widthFixed) { var d = $('<colgroup>'); $("tr:first td", a.tBodies[0]).each(function() { d.append($('<col>').css('width', $(this).width())) }); $(a).prepend(d) } } function updateHeaderSortCount(a, b) { var c = a.config, l = b.length; for (var i = 0; i < l; i++) { var s = b[i], o = c.headerList[s[0]]; o.count = s[1]; o.count++ } } function multisort(a, b, d) { if (a.config.debug) { var f = new Date() } var g = "var sortWrapper = function(a,b) {", l = b.length; for (var i = 0; i < l; i++) { var c = b[i][0]; var h = b[i][1]; var s = (getCachedSortType(a.config.parsers, c) == "text") ? ((h == 0) ? "sortText" : "sortTextDesc") : ((h == 0) ? "sortNumeric" : "sortNumericDesc"); var e = "e" + i; g += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); "; g += "if(" + e + ") { return " + e + "; } "; g += "else { " } var j = d.normalized[0].length - 1; g += "return a[" + j + "]-b[" + j + "];"; for (var i = 0; i < l; i++) { g += "}; " } g += "return 0; "; g += "}; "; eval(g); d.normalized.sort(sortWrapper); if (a.config.debug) { benchmark("Sorting on " + b.toString() + " and dir " + h + " time:", f) } return d }; function sortText(a, b) { return ((a < b) ? -1 : ((a > b) ? 1 : 0)) }; function sortTextDesc(a, b) { return ((b < a) ? -1 : ((b > a) ? 1 : 0)) }; function sortNumeric(a, b) { return a - b }; function sortNumericDesc(a, b) { return b - a }; function getCachedSortType(a, i) { return a[i].type }; this.construct = function(h) { return this.each(function() { if (!this.tHead || !this.tBodies) return; var f, $document, $headers, cache, config, shiftDown = 0, sortOrder; this.config = {}; config = $.extend(this.config, $.tablesorter.defaults, h); f = $(this); $headers = buildHeaders(this); this.config.parsers = buildParserCache(this, $headers); cache = buildCache(this); var g = [config.cssDesc, config.cssAsc]; fixColumnWidth(this); $headers.click(function(e) { f.trigger("sortStart"); var b = (f[0].tBodies[0] && f[0].tBodies[0].rows.length) || 0; if (!this.sortDisabled && b > 0) { var c = $(this); var i = this.column; this.order = this.count++ % 2; var d = this.order; if (!e[config.sortMultiSortKey]) { config.sortList = []; if (config.sortForce != null) { var a = config.sortForce; for (var j = 0; j < a.length; j++) { if (a[j][0] != i) { config.sortList.push(a[j]) } } } config.sortList.push([i, this.order]) } else { if (isValueInArray(i, config.sortList)) { 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 { config.sortList.push([i, this.order]) } }; setTimeout(function() { setHeadersCss(f[0], $headers, config.sortList, g); appendToTable(f[0], multisort(f[0], config.sortList, cache)); j$('table.tablesorter tbody tr').each(function() { var a = j$(this).attr('name'); if (a != null) { j$(this).unbind('click').click(function() { location.href = a + 'order=' + i + '&sortdirection=' + d }) } }); j$('#SortedColumn').attr('value', i); j$('#SortDirection').attr('value', d) }, 1); return false } }).mousedown(function() { if (config.cancelSelection) { this.onselectstart = function() { return false }; return false } }); f.bind("update", function() { this.config.parsers = buildParserCache(this, $headers); cache = buildCache(this) }).bind("sorton", function(e, a) { $(this).trigger("sortStart"); config.sortList = a; var b = config.sortList; updateHeaderSortCount(this, b); setHeadersCss(this, $headers, b, g); appendToTable(this, multisort(this, b, cache)) }).bind("appendCache", function() { appendToTable(this, cache) }).bind("applyWidgetId", function(e, a) { getWidgetById(a).format(this) }).bind("applyWidgets", function() { applyWidget(this) }); if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) { config.sortList = $(this).metadata().sortlist } if (config.sortList.length > 0) { f.trigger("sorton", [config.sortList]) } applyWidget(this) }) }; this.addParser = function(b) { var l = k.length, a = true; for (var i = 0; i < l; i++) { if (k[i].id.toLowerCase() == b.id.toLowerCase()) { a = false } } if (a) { k.push(b) } }; this.addWidget = function(a) { widgets.push(a) }; this.formatFloat = function(s) { var i = parseFloat(s); return (isNaN(i)) ? 0 : i }; this.formatInt = function(s) { var i = parseInt(s); return (isNaN(i)) ? 0 : i }; this.isDigit = function(s, a) { var b = '\\' + a.decimal; var c = '/(^[+]?0(' + b + '0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + b + '(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + b + '0+$)/'; return RegExp(c).test($.trim(s)) }; this.clearTableBody = function(a) { if ($.browser.msie) { function empty() { while (this.firstChild) this.removeChild(this.firstChild) } empty.apply(a.tBodies[0]) } else { a.tBodies[0].innerHTML = "" } } } }); $.fn.extend({ tablesorter: $.tablesorter.construct }); var m = $.tablesorter; m.addParser({ id: "text", is: function(s) { return true }, format: function(s) { return $.trim(s.toLowerCase()) }, type: "text" }); m.addParser({ id: "digit", is: function(s, a) { var c = a.config; return $.tablesorter.isDigit(s, c) }, format: function(s) { return $.tablesorter.formatFloat(s) }, type: "numeric" }); m.addParser({ id: "currency", is: function(s) { return /^[£$€?.]/.test(s) }, format: function(s) { return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g), "")) }, type: "numeric" }); m.addParser({ id: "ipAddress", is: function(s) { return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s) }, format: function(s) { var a = s.split("."), r = "", l = a.length; for (var i = 0; i < l; i++) { var b = a[i]; if (b.length == 2) { r += "0" + b } else { r += b } } return $.tablesorter.formatFloat(r) }, type: "numeric" }); m.addParser({ id: "url", is: function(s) { return /^(https?|ftp|file):\/\/$/.test(s) }, format: function(s) { return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), '')) }, type: "text" }); m.addParser({ id: "isoDate", is: function(s) { return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s) }, format: function(s) { return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g), "/")).getTime() : "0") }, type: "numeric" }); m.addParser({ id: "percent", is: function(s) { return /\%$/.test($.trim(s)) }, format: function(s) { return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), "")) }, type: "numeric" }); m.addParser({ id: "usLongDate", is: function(s) { return s.match(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)))$/)) }, format: function(s) { return $.tablesorter.formatFloat(new Date(s).getTime()) }, type: "numeric" }); m.addParser({ id: "shortDate", is: function(s) { return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s); }, format: function(s, table) { var c = table.config; s = s.replace(/\-/g, "/"); if (c.dateFormat == "us") { s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2") } else if (c.dateFormat == "uk") { s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1") } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") { s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3") } return $.tablesorter.formatFloat(new Date(s).getTime()) }, type: "numeric" }); m.addParser({ id: "time", is: function(s) { return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s) }, format: function(s) { return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime()) }, type: "numeric" }); m.addParser({ id: "metadata", is: function(s) { return false }, format: function(s, a, b) { var c = a.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; return $(b).metadata()[p] }, type: "numeric" }); m.addWidget({ id: "zebra", format: function(a) { if (a.config.debug) { var b = new Date() } $("tr:visible", a.tBodies[0]).filter(':even').removeClass(a.config.widgetZebra.css[1]).addClass(a.config.widgetZebra.css[0]).end().filter(':odd').removeClass(a.config.widgetZebra.css[0]).addClass(a.config.widgetZebra.css[1]); if (a.config.debug) { $.tablesorter.benchmark("Applying Zebra widget", b) } } }) })(jQuery);