| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 | /* *  * TableSorter 2.0 - Client-side table sorting with ease! * Version 2.0 * @requires jQuery v1.1.3 *  * Copyright (c) 2007 Christian Bach * Examples and docs at: http://tablesorter.com * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html *  *//** * * @description Create a sortable table with multi-column sorting capabilitys *  * @example $('#table').tablesorter(); * @desc Create a simple tablesorter interface. * * @example $('#table').tablesorter({ sortList:[[0,0],[1,0]] }); * @desc Create a tablesorter interface and sort on the first and secound column in ascending order. *  * @example $('#table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } }); * @desc Create a tablesorter interface and disableing the first and secound column headers. *  * @example $('#table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} }); * @desc Create a tablesorter interface and set a column parser for the first and secound column. *  *  * @param Object settings An object literal containing key/value pairs to provide optional settings. *  * @option String cssHeader (optional) 			A string of the class name to be appended to sortable tr elements in the thead of the table.  * 												Default value: "header" *  * @option String cssAsc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a ascending sort.  * 												Default value: "headerSortUp" *  * @option String cssDesc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a descending sort.  * 												Default value: "headerSortDown" *  * @option String sortInitialOrder (optional) 	A string of the inital sorting order can be asc or desc.  * 												Default value: "asc" *  * @option String sortMultisortKey (optional) 	A string of the multi-column sort key.  * 												Default value: "shiftKey" *  * @option String textExtraction (optional) 	A string of the text-extraction method to use.  * 												For complex html structures inside td cell set this option to "complex",  * 												on large tables the complex option can be slow.  * 												Default value: "simple" *  * @option Object headers (optional) 			An array containing the forces sorting rules.  * 												This option let's you specify a default sorting rule.  * 												Default value: null *  * @option Array sortList (optional) 			An array containing the forces sorting rules.  * 												This option let's you specify a default sorting rule.  * 												Default value: null *  * @option Array sortForce (optional) 			An array containing the forces sorting rules.  * 												This option let's you specify a default sorting rule.  * 												Default value: null *   *  * @option Boolean widthFixed (optional) 		Boolean flag indicating if tablesorter should apply fixed widths to the table columns. * 												This is usefull when using the pager companion plugin. * 												This options requires the dimension jquery plugin. * 												Default value: false * * @option Boolean cancelSelection (optional) 	Boolean flag indicating if tablesorter should cancel selection of the table headers text. * 												Default value: true *  * @type jQuery * * @name tablesorter *  * @cat Plugins/Tablesorter *  * @author Christian Bach/christian.bach@polyester.se */(function($) {	$.extend({		tablesorter: new function() {						var parsers = [], widgets = [];						this.defaults = {				cssHeader: "header",				cssAsc: "headerSortUp",				cssDesc: "headerSortDown",				sortInitialOrder: "asc",				sortMultiSortKey: "shiftKey",				sortForce: null,				textExtraction: "simple",				parsers: {}, 				widgets: [],						widgetZebra: {css: ["even","odd"]},				headers: {},				widthFixed: false,				cancelSelection: true,				sortList: [],				headerList: [],				dateFormat: "us",				debug: false			};						/* debuging utils */			function benchmark(label,stamp) {				log(label + "," + (new Date().getTime() - stamp.getTime()) + "ms");			}						function log(s) {				if (typeof console != "undefined" && typeof console.debug != "undefined") {					console.log(s);				} else {					alert(s);				}			}									/* parsers utils */			function buildParserCache(table,$headers) {								if(table.config.debug) { var parsersDebug = ""; }								var list = [], cells = table.tBodies[0].rows[0].cells, l = cells.length;								for (var i=0;i < l; i++) {					var p = false;										if($.meta && ($($headers[i]).data() && $($headers[i]).data().sorter)  ) {											p = getParserById($($headers[i]).data().sorter);											} else if((table.config.headers[i] && table.config.headers[i].sorter)) {						p = getParserById(table.config.headers[i].sorter);					}					if(!p) {						p = detectParserForColumn(table.config,cells[i]);					}					if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }					list.push(p);				}				if(table.config.debug) { log(parsersDebug); }				return list;			};						function detectParserForColumn(config,node) {				var l = parsers.length;				for(var i=1; i < l; i++) {					if(parsers[i].is($.trim(getElementText(config,node)))) {						return parsers[i];					}				}								// 0 is always the generic parser (text)				return parsers[0];			}						function getParserById(name) {				var l = parsers.length;				for(var i=0; i < l; i++) {					if(parsers[i].id.toLowerCase() == name.toLowerCase()) {							return parsers[i];					}				}				return false;			}						/* utils */			function buildCache(table) {								if(table.config.debug) { var cacheTime = new Date(); }								var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,					totalCells = table.tBodies[0].rows[0].cells.length,					parsers = table.config.parsers, 					cache = {row: [], normalized: []};									for (var i=0;i < totalRows; ++i) {											/** Add the table data to main data array */						var c = table.tBodies[0].rows[i], cols = [];											cache.row.push($(c));												for(var j=0; j < totalCells; ++j) {							cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));							}																		cols.push(i); // add position for rowCache						cache.normalized.push(cols);						cols = null;					};								if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }								return cache;			};						function getElementText(config,node) {								if(!node) return "";												var t = "";												if(typeof(config.textExtraction) == "function") {					t = config.textExtraction(node);				} else if(config.textExtraction == "complex") { 					t = $(node).text();				} else {					if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {						t = node.childNodes[0].innerHTML;					} else {						t = node.innerHTML;					}				}				return t;			}						function appendToTable(table,cache) {								if(table.config.debug) {var appendTime = new Date()}								var c = cache, 					r = c.row, 					n= c.normalized, 					totalRows = n.length, 					checkCell = (n[0].length-1), 					tableBody = $("tbody:first",table).empty();					rows = [];								for (var i=0;i < totalRows; i++) {					 	rows.push(r[n[i][checkCell]]);						if(table.config.appender == null) {							tableBody.append(r[n[i][checkCell]]);						}				}					if(table.config.appender != null) {					table.config.appender(table,rows);					}								rows = null;								//apply table widgets				applyWidget(table);								if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }						};						function buildHeaders(table) {								if(table.config.debug) { var time = new Date(); }								var meta = ($.meta) ? true : false, tableHeadersRows = [];							for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };								$tableHeaders = $(checkCellColSpan(table, tableHeadersRows, 0,table.tHead.rows[0].cells.length));						$tableHeaders.each(function(index) {												this.count = 0;					this.column = index;					this.order = formatSortingOrder(table.config.sortInitialOrder);										if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;										if(!this.sortDisabled) {						$(this).addClass(table.config.cssHeader);					}										// add cell to headerList					table.config.headerList[index]= this;				});								if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }								return $tableHeaders;							};								   	function checkCellColSpan(table, headerArr, row) {                var arr = [], r = table.tHead.rows, c = r[row].cells;								for(var i=headerArr[row]; i < c.length; i++) {					var cell = c[i];										if ( cell.colSpan > 1) { 						arr = arr.concat(checkCellColSpan(table, headerArr,row+cell.rowSpan));					} else  {						if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {							arr.push(cell);						}						headerArr[row] = (i+row);					}				}				return arr;			};						function checkHeaderMetadata(cell) {				if(($.meta) && ($(cell).data().sorter === false)) { return true; };				return false;			}						function checkHeaderOptions(table,i) {					if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };				return false;			}						function applyWidget(table) {				var c = table.config.widgets;				var l = c.length;				for(var i=0; i < l; i++) {										getWidgetById(c[i]).format(table);				}							}						function getWidgetById(name) {				var l = widgets.length;				for(var i=0; i < l; i++) {					if(widgets[i].id.toLowerCase() == name.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(table,$headers, list, css) {				// remove all header information				$headers.removeClass(css[0]).removeClass(css[1]);								var h = [];				$headers.each(function(offset) {						if(!this.sortDisabled) {							h[this.column] = $(this);											}				});				var l = list.length; 				for(var i=0; i < l; i++) {					h[list[i][0]].addClass(css[list[i][1]]);				}			}						function fixColumnWidth(table,$headers) {				var c = table.config;				if(c.widthFixed) {					var colgroup = $('<colgroup>');					$("tbody:first tr:first td",table).each(function() {												colgroup.append($('<col>').css('width',$(this).width()));										});					$(table).prepend(colgroup);				};			}						function updateHeaderSortCount(table,sortList) {				var c = table.config, l = sortList.length;				for(var i=0; i < l; i++) {					var s = sortList[i], o = c.headerList[s[0]];					o.count = s[1];					o.count++;				}			}						/* sorting methods */			function multisort(table,sortList,cache) {								if(table.config.debug) { var sortTime = new Date(); }								var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;									for(var i=0; i < l; i++) {										var c = sortList[i][0];					var order = sortList[i][1];					var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");										var e = "e" + i;										dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";					dynamicExp += "if(" + e + ") { return " + e + "; } ";					dynamicExp += "else { ";				}									for(var i=0; i < l; i++) {					dynamicExp += "}; ";				}								dynamicExp += "return 0; ";					dynamicExp += "}; ";									eval(dynamicExp);								cache.normalized.sort(sortWrapper);								if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }								return cache;			};						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(parsers,i) {				return parsers[i].type;			};						/* public methods */			this.construct = function(settings) {				return this.each(function() {																									var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;										this.config = {};										config = $.extend(this.config, $.tablesorter.defaults, settings);										if(!this.tHead || !this.tBodies) return true;										// store common expression for speed										$this = $(this);										// build headers					$headers = buildHeaders(this);										// try to auto detect column type, and store in tables config					this.config.parsers = buildParserCache(this,$headers);															// build the cache for the tbody cells					cache = buildCache(this);										// get the css class names, could be done else where.					var sortCSS = [config.cssDesc,config.cssAsc];										// fixate columns if the users supplies the fixedWidth option					fixColumnWidth(this);										// apply event handling to headers					// this is to big, perhaps break it out?					$headers.click(function(e) {						if(!this.sortDisabled) {							// store exp, for speed							var $cell = $(this);								// get current column index							var i = this.column;														// get current column sort order							this.order = this.count++ % 2;																												// user only whants to sort on one column							if(!e[config.sortMultiSortKey]) {																// flush the sort list								config.sortList = [];																if(config.sortForce != null) {									var a = config.sortForce; 									for(var j=0; j < a.length; j++) { 											config.sortList.push(a[j]);										}								}																// add column to sort list								config.sortList.push([i,this.order]);														// multi column sorting								} else {								// the user has clicked on an all ready sortet column.								if(isValueInArray(i,config.sortList)) {	 																		// revers the sorting direction for all tables.									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 {									// add column to sort list array									config.sortList.push([i,this.order]);								}							};														//set css for headers							setHeadersCss($this[0],$headers,config.sortList,sortCSS);														// sort the table and append it to the dom							appendToTable($this[0],multisort($this[0],config.sortList,cache));														// stop normal event by returning false							return false;						}					// cancel selection						}).mousedown(function() {						if(config.cancelSelection) {							this.onselectstart = function() {return false};							//alert(this.onselectstart);							return false;						}					});										// apply easy methods that trigger binded events					$this.bind("update",function() {												// rebuild the cache map						cache = buildCache(this);											}).bind("sorton",function(e,list) {												// update and store the sortlist						var sortList = config.sortList = list;												// update header count index						updateHeaderSortCount(this,sortList);												//set css for headers						setHeadersCss(this,$headers,sortList,sortCSS);												// sort the table and append it to the dom						appendToTable(this,multisort(this,sortList,cache));											}).bind("appendCache",function() {												appendToTable(this,cache);										}).bind("applyWidgetId",function(e,id) {												getWidgetById(id).format(this);											});										if($.meta && ($(this).data() && $(this).data().sortlist)) {						config.sortList = $(this).data().sortlist;					}					// if user has supplied a sort list to constructor.					if(config.sortList.length > 0) {						$this.trigger("sorton",[config.sortList]);						}										// apply widgets					applyWidget(this);				});			};						this.addParser = function(parser) {				var l = parsers.length, a = true;				for(var i=0; i < l; i++) {					if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {						a = false;					}				}				if(a) { parsers.push(parser); };			};						this.addWidget = function(widget) {				widgets.push(widget);			};						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;			};					}	});		// extend plugin scope	$.fn.extend({        tablesorter: $.tablesorter.construct	});		// add default parsers	$.tablesorter.addParser({		id: "text",		is: function(s) {			return true;		},		format: function(s) {			return $.trim(s.toLowerCase());		},		type: "text"	});		$.tablesorter.addParser({		id: "integer",		is: function(s) {			return s.match(new RegExp(/^\d+$/));		},		format: function(s) {			return $.tablesorter.formatInt(s);		},		type: "numeric"	});		$.tablesorter.addParser({		id: "currency",		is: function(s) {			return /^[£$€?.]/.test(s);		},		format: function(s) {			return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));		},		type: "numeric"	});		$.tablesorter.addParser({		id: "integer",		is: function(s) {			return /^\d+$/.test(s);		},		format: function(s) {			return $.tablesorter.formatFloat(s);		},		type: "numeric"	});		$.tablesorter.addParser({		id: "floating",		is: function(s) {			return s.match(new RegExp(/^(\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?$/));		},		format: function(s) {			return $.tablesorter.formatFloat(s.replace(new RegExp(/,/),""));		},		type: "numeric"	});		$.tablesorter.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(".");			var r = "";			for (var i = 0, item; item = a[i]; i++) {			   if(item.length == 2) {					r += "0" + item;			   } else {					r += item;			   }			}			return $.tablesorter.formatFloat(s);		},		type: "numeric"	});		$.tablesorter.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"	});		$.tablesorter.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"	});		$.tablesorter.addParser({		id: "percent",		is: function(s) {			return /^\d{1,3}%$/.test(s);		},		format: function(s) {			return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));		},		type: "numeric"	});		$.tablesorter.addParser({		id: "usLongDate",		is: function(s) {			return /^[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)))$/.test(s);		},		format: function(s) {			return $.tablesorter.formatFloat(new Date(s).getTime());		},		type: "numeric"	});		$.tablesorter.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(new RegExp(/-/g),"/");			if(c.dateFormat == "us") {				/** reformat the string in ISO format */				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$1/$2");			} else if(c.dateFormat == "uk") {				/** reformat the string in ISO format */				s = s.replace(new RegExp(/(\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(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2})/), "$1/$2/$3");				}			return $.tablesorter.formatFloat(new Date(s).getTime());		},		type: "numeric"	});		$.tablesorter.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"	});			$.tablesorter.addParser({	    id: "metadata",	    is: function(s) {	        return false;	    },	    format: function(s,table,cell) {			var c = table.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;	        return $(cell).data()[p];	    },	  type: "numeric"	});		// add default widgets	$.tablesorter.addWidget({		id: "zebra",		format: function(table) {			$("> tbody:first/tr:visible:even",table).removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]);			$("> tbody:first/tr:visible:odd",table).removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);		}	});	})(jQuery);
 |