ui.tablesorter.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. *
  3. * TableSorter 2.0 - Client-side table sorting with ease!
  4. * Version 2.0
  5. * @requires jQuery v1.1.3
  6. *
  7. * Copyright (c) 2007 Christian Bach
  8. * Examples and docs at: http://tablesorter.com
  9. * Dual licensed under the MIT and GPL licenses:
  10. * http://www.opensource.org/licenses/mit-license.php
  11. * http://www.gnu.org/licenses/gpl.html
  12. *
  13. */
  14. /**
  15. *
  16. * @description Create a sortable table with multi-column sorting capabilitys
  17. *
  18. * @example $('#table').tablesorter();
  19. * @desc Create a simple tablesorter interface.
  20. *
  21. * @example $('#table').tablesorter({ sortList:[[0,0],[1,0]] });
  22. * @desc Create a tablesorter interface and sort on the first and secound column in ascending order.
  23. *
  24. * @example $('#table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
  25. * @desc Create a tablesorter interface and disableing the first and secound column headers.
  26. *
  27. * @example $('#table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} });
  28. * @desc Create a tablesorter interface and set a column parser for the first and secound column.
  29. *
  30. *
  31. * @param Object settings An object literal containing key/value pairs to provide optional settings.
  32. *
  33. * @option String cssHeader (optional) A string of the class name to be appended to sortable tr elements in the thead of the table.
  34. * Default value: "header"
  35. *
  36. * @option String cssAsc (optional) A string of the class name to be appended to sortable tr elements in the thead on a ascending sort.
  37. * Default value: "headerSortUp"
  38. *
  39. * @option String cssDesc (optional) A string of the class name to be appended to sortable tr elements in the thead on a descending sort.
  40. * Default value: "headerSortDown"
  41. *
  42. * @option String sortInitialOrder (optional) A string of the inital sorting order can be asc or desc.
  43. * Default value: "asc"
  44. *
  45. * @option String sortMultisortKey (optional) A string of the multi-column sort key.
  46. * Default value: "shiftKey"
  47. *
  48. * @option String textExtraction (optional) A string of the text-extraction method to use.
  49. * For complex html structures inside td cell set this option to "complex",
  50. * on large tables the complex option can be slow.
  51. * Default value: "simple"
  52. *
  53. * @option Object headers (optional) An array containing the forces sorting rules.
  54. * This option let's you specify a default sorting rule.
  55. * Default value: null
  56. *
  57. * @option Array sortList (optional) An array containing the forces sorting rules.
  58. * This option let's you specify a default sorting rule.
  59. * Default value: null
  60. *
  61. * @option Array sortForce (optional) An array containing the forces sorting rules.
  62. * This option let's you specify a default sorting rule.
  63. * Default value: null
  64. *
  65. *
  66. * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter should apply fixed widths to the table columns.
  67. * This is usefull when using the pager companion plugin.
  68. * This options requires the dimension jquery plugin.
  69. * Default value: false
  70. *
  71. * @option Boolean cancelSelection (optional) Boolean flag indicating if tablesorter should cancel selection of the table headers text.
  72. * Default value: true
  73. *
  74. * @type jQuery
  75. *
  76. * @name tablesorter
  77. *
  78. * @cat Plugins/Tablesorter
  79. *
  80. * @author Christian Bach/christian.bach@polyester.se
  81. */
  82. (function($) {
  83. $.extend({
  84. tablesorter: new function() {
  85. var parsers = [], widgets = [];
  86. this.defaults = {
  87. cssHeader: "header",
  88. cssAsc: "headerSortUp",
  89. cssDesc: "headerSortDown",
  90. sortInitialOrder: "asc",
  91. sortMultiSortKey: "shiftKey",
  92. sortForce: null,
  93. textExtraction: "simple",
  94. parsers: {},
  95. widgets: [],
  96. widgetZebra: {css: ["even","odd"]},
  97. headers: {},
  98. widthFixed: false,
  99. cancelSelection: true,
  100. sortList: [],
  101. headerList: [],
  102. dateFormat: "us",
  103. debug: false
  104. };
  105. /* debuging utils */
  106. function benchmark(label,stamp) {
  107. log(label + "," + (new Date().getTime() - stamp.getTime()) + "ms");
  108. }
  109. function log(s) {
  110. if (typeof console != "undefined" && typeof console.debug != "undefined") {
  111. console.log(s);
  112. } else {
  113. alert(s);
  114. }
  115. }
  116. /* parsers utils */
  117. function buildParserCache(table,$headers) {
  118. if(table.config.debug) { var parsersDebug = ""; }
  119. var list = [], cells = table.tBodies[0].rows[0].cells, l = cells.length;
  120. for (var i=0;i < l; i++) {
  121. var p = false;
  122. if($.meta && ($($headers[i]).data() && $($headers[i]).data().sorter) ) {
  123. p = getParserById($($headers[i]).data().sorter);
  124. } else if((table.config.headers[i] && table.config.headers[i].sorter)) {
  125. p = getParserById(table.config.headers[i].sorter);
  126. }
  127. if(!p) {
  128. p = detectParserForColumn(table.config,cells[i]);
  129. }
  130. if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }
  131. list.push(p);
  132. }
  133. if(table.config.debug) { log(parsersDebug); }
  134. return list;
  135. };
  136. function detectParserForColumn(config,node) {
  137. var l = parsers.length;
  138. for(var i=1; i < l; i++) {
  139. if(parsers[i].is($.trim(getElementText(config,node)))) {
  140. return parsers[i];
  141. }
  142. }
  143. // 0 is always the generic parser (text)
  144. return parsers[0];
  145. }
  146. function getParserById(name) {
  147. var l = parsers.length;
  148. for(var i=0; i < l; i++) {
  149. if(parsers[i].id.toLowerCase() == name.toLowerCase()) {
  150. return parsers[i];
  151. }
  152. }
  153. return false;
  154. }
  155. /* utils */
  156. function buildCache(table) {
  157. if(table.config.debug) { var cacheTime = new Date(); }
  158. var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
  159. totalCells = table.tBodies[0].rows[0].cells.length,
  160. parsers = table.config.parsers,
  161. cache = {row: [], normalized: []};
  162. for (var i=0;i < totalRows; ++i) {
  163. /** Add the table data to main data array */
  164. var c = table.tBodies[0].rows[i], cols = [];
  165. cache.row.push($(c));
  166. for(var j=0; j < totalCells; ++j) {
  167. cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));
  168. }
  169. cols.push(i); // add position for rowCache
  170. cache.normalized.push(cols);
  171. cols = null;
  172. };
  173. if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }
  174. return cache;
  175. };
  176. function getElementText(config,node) {
  177. if(!node) return "";
  178. var t = "";
  179. if(typeof(config.textExtraction) == "function") {
  180. t = config.textExtraction(node);
  181. } else if(config.textExtraction == "complex") {
  182. t = $(node).text();
  183. } else {
  184. if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
  185. t = node.childNodes[0].innerHTML;
  186. } else {
  187. t = node.innerHTML;
  188. }
  189. }
  190. return t;
  191. }
  192. function appendToTable(table,cache) {
  193. if(table.config.debug) {var appendTime = new Date()}
  194. var c = cache,
  195. r = c.row,
  196. n= c.normalized,
  197. totalRows = n.length,
  198. checkCell = (n[0].length-1),
  199. tableBody = $("tbody:first",table).empty();
  200. rows = [];
  201. for (var i=0;i < totalRows; i++) {
  202. rows.push(r[n[i][checkCell]]);
  203. if(table.config.appender == null) {
  204. tableBody.append(r[n[i][checkCell]]);
  205. }
  206. }
  207. if(table.config.appender != null) {
  208. table.config.appender(table,rows);
  209. }
  210. rows = null;
  211. //apply table widgets
  212. applyWidget(table);
  213. if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }
  214. };
  215. function buildHeaders(table) {
  216. if(table.config.debug) { var time = new Date(); }
  217. var meta = ($.meta) ? true : false, tableHeadersRows = [];
  218. for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };
  219. $tableHeaders = $(checkCellColSpan(table, tableHeadersRows, 0,table.tHead.rows[0].cells.length));
  220. $tableHeaders.each(function(index) {
  221. this.count = 0;
  222. this.column = index;
  223. this.order = formatSortingOrder(table.config.sortInitialOrder);
  224. if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;
  225. if(!this.sortDisabled) {
  226. $(this).addClass(table.config.cssHeader);
  227. }
  228. // add cell to headerList
  229. table.config.headerList[index]= this;
  230. });
  231. if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }
  232. return $tableHeaders;
  233. };
  234. function checkCellColSpan(table, headerArr, row) {
  235. var arr = [], r = table.tHead.rows, c = r[row].cells;
  236. for(var i=headerArr[row]; i < c.length; i++) {
  237. var cell = c[i];
  238. if ( cell.colSpan > 1) {
  239. arr = arr.concat(checkCellColSpan(table, headerArr,row+cell.rowSpan));
  240. } else {
  241. if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {
  242. arr.push(cell);
  243. }
  244. headerArr[row] = (i+row);
  245. }
  246. }
  247. return arr;
  248. };
  249. function checkHeaderMetadata(cell) {
  250. if(($.meta) && ($(cell).data().sorter === false)) { return true; };
  251. return false;
  252. }
  253. function checkHeaderOptions(table,i) {
  254. if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };
  255. return false;
  256. }
  257. function applyWidget(table) {
  258. var c = table.config.widgets;
  259. var l = c.length;
  260. for(var i=0; i < l; i++) {
  261. getWidgetById(c[i]).format(table);
  262. }
  263. }
  264. function getWidgetById(name) {
  265. var l = widgets.length;
  266. for(var i=0; i < l; i++) {
  267. if(widgets[i].id.toLowerCase() == name.toLowerCase() ) {
  268. return widgets[i];
  269. }
  270. }
  271. };
  272. function formatSortingOrder(v) {
  273. if(typeof(v) != "Number") {
  274. i = (v.toLowerCase() == "desc") ? 1 : 0;
  275. } else {
  276. i = (v == (0 || 1)) ? v : 0;
  277. }
  278. return i;
  279. }
  280. function isValueInArray(v, a) {
  281. var l = a.length;
  282. for(var i=0; i < l; i++) {
  283. if(a[i][0] == v) {
  284. return true;
  285. }
  286. }
  287. return false;
  288. }
  289. function setHeadersCss(table,$headers, list, css) {
  290. // remove all header information
  291. $headers.removeClass(css[0]).removeClass(css[1]);
  292. var h = [];
  293. $headers.each(function(offset) {
  294. if(!this.sortDisabled) {
  295. h[this.column] = $(this);
  296. }
  297. });
  298. var l = list.length;
  299. for(var i=0; i < l; i++) {
  300. h[list[i][0]].addClass(css[list[i][1]]);
  301. }
  302. }
  303. function fixColumnWidth(table,$headers) {
  304. var c = table.config;
  305. if(c.widthFixed) {
  306. var colgroup = $('<colgroup>');
  307. $("tbody:first tr:first td",table).each(function() {
  308. colgroup.append($('<col>').css('width',$(this).width()));
  309. });
  310. $(table).prepend(colgroup);
  311. };
  312. }
  313. function updateHeaderSortCount(table,sortList) {
  314. var c = table.config, l = sortList.length;
  315. for(var i=0; i < l; i++) {
  316. var s = sortList[i], o = c.headerList[s[0]];
  317. o.count = s[1];
  318. o.count++;
  319. }
  320. }
  321. /* sorting methods */
  322. function multisort(table,sortList,cache) {
  323. if(table.config.debug) { var sortTime = new Date(); }
  324. var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;
  325. for(var i=0; i < l; i++) {
  326. var c = sortList[i][0];
  327. var order = sortList[i][1];
  328. var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
  329. var e = "e" + i;
  330. dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";
  331. dynamicExp += "if(" + e + ") { return " + e + "; } ";
  332. dynamicExp += "else { ";
  333. }
  334. for(var i=0; i < l; i++) {
  335. dynamicExp += "}; ";
  336. }
  337. dynamicExp += "return 0; ";
  338. dynamicExp += "}; ";
  339. eval(dynamicExp);
  340. cache.normalized.sort(sortWrapper);
  341. if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }
  342. return cache;
  343. };
  344. function sortText(a,b) {
  345. return ((a < b) ? -1 : ((a > b) ? 1 : 0));
  346. };
  347. function sortTextDesc(a,b) {
  348. return ((b < a) ? -1 : ((b > a) ? 1 : 0));
  349. };
  350. function sortNumeric(a,b) {
  351. return a-b;
  352. };
  353. function sortNumericDesc(a,b) {
  354. return b-a;
  355. };
  356. function getCachedSortType(parsers,i) {
  357. return parsers[i].type;
  358. };
  359. /* public methods */
  360. this.construct = function(settings) {
  361. return this.each(function() {
  362. var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;
  363. this.config = {};
  364. config = $.extend(this.config, $.tablesorter.defaults, settings);
  365. if(!this.tHead || !this.tBodies) return true;
  366. // store common expression for speed
  367. $this = $(this);
  368. // build headers
  369. $headers = buildHeaders(this);
  370. // try to auto detect column type, and store in tables config
  371. this.config.parsers = buildParserCache(this,$headers);
  372. // build the cache for the tbody cells
  373. cache = buildCache(this);
  374. // get the css class names, could be done else where.
  375. var sortCSS = [config.cssDesc,config.cssAsc];
  376. // fixate columns if the users supplies the fixedWidth option
  377. fixColumnWidth(this);
  378. // apply event handling to headers
  379. // this is to big, perhaps break it out?
  380. $headers.click(function(e) {
  381. if(!this.sortDisabled) {
  382. // store exp, for speed
  383. var $cell = $(this);
  384. // get current column index
  385. var i = this.column;
  386. // get current column sort order
  387. this.order = this.count++ % 2;
  388. // user only whants to sort on one column
  389. if(!e[config.sortMultiSortKey]) {
  390. // flush the sort list
  391. config.sortList = [];
  392. if(config.sortForce != null) {
  393. var a = config.sortForce;
  394. for(var j=0; j < a.length; j++) {
  395. config.sortList.push(a[j]);
  396. }
  397. }
  398. // add column to sort list
  399. config.sortList.push([i,this.order]);
  400. // multi column sorting
  401. } else {
  402. // the user has clicked on an all ready sortet column.
  403. if(isValueInArray(i,config.sortList)) {
  404. // revers the sorting direction for all tables.
  405. for(var j=0; j < config.sortList.length; j++) {
  406. var s = config.sortList[j], o = config.headerList[s[0]];
  407. if(s[0] == i) {
  408. o.count = s[1];
  409. o.count++;
  410. s[1] = o.count % 2;
  411. }
  412. }
  413. } else {
  414. // add column to sort list array
  415. config.sortList.push([i,this.order]);
  416. }
  417. };
  418. //set css for headers
  419. setHeadersCss($this[0],$headers,config.sortList,sortCSS);
  420. // sort the table and append it to the dom
  421. appendToTable($this[0],multisort($this[0],config.sortList,cache));
  422. // stop normal event by returning false
  423. return false;
  424. }
  425. // cancel selection
  426. }).mousedown(function() {
  427. if(config.cancelSelection) {
  428. this.onselectstart = function() {return false};
  429. //alert(this.onselectstart);
  430. return false;
  431. }
  432. });
  433. // apply easy methods that trigger binded events
  434. $this.bind("update",function() {
  435. // rebuild the cache map
  436. cache = buildCache(this);
  437. }).bind("sorton",function(e,list) {
  438. // update and store the sortlist
  439. var sortList = config.sortList = list;
  440. // update header count index
  441. updateHeaderSortCount(this,sortList);
  442. //set css for headers
  443. setHeadersCss(this,$headers,sortList,sortCSS);
  444. // sort the table and append it to the dom
  445. appendToTable(this,multisort(this,sortList,cache));
  446. }).bind("appendCache",function() {
  447. appendToTable(this,cache);
  448. }).bind("applyWidgetId",function(e,id) {
  449. getWidgetById(id).format(this);
  450. });
  451. if($.meta && ($(this).data() && $(this).data().sortlist)) {
  452. config.sortList = $(this).data().sortlist;
  453. }
  454. // if user has supplied a sort list to constructor.
  455. if(config.sortList.length > 0) {
  456. $this.trigger("sorton",[config.sortList]);
  457. }
  458. // apply widgets
  459. applyWidget(this);
  460. });
  461. };
  462. this.addParser = function(parser) {
  463. var l = parsers.length, a = true;
  464. for(var i=0; i < l; i++) {
  465. if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
  466. a = false;
  467. }
  468. }
  469. if(a) { parsers.push(parser); };
  470. };
  471. this.addWidget = function(widget) {
  472. widgets.push(widget);
  473. };
  474. this.formatFloat = function(s) {
  475. var i = parseFloat(s);
  476. return (isNaN(i)) ? 0 : i;
  477. };
  478. this.formatInt = function(s) {
  479. var i = parseInt(s);
  480. return (isNaN(i)) ? 0 : i;
  481. };
  482. }
  483. });
  484. // extend plugin scope
  485. $.fn.extend({
  486. tablesorter: $.tablesorter.construct
  487. });
  488. // add default parsers
  489. $.tablesorter.addParser({
  490. id: "text",
  491. is: function(s) {
  492. return true;
  493. },
  494. format: function(s) {
  495. return $.trim(s.toLowerCase());
  496. },
  497. type: "text"
  498. });
  499. $.tablesorter.addParser({
  500. id: "integer",
  501. is: function(s) {
  502. return s.match(new RegExp(/^\d+$/));
  503. },
  504. format: function(s) {
  505. return $.tablesorter.formatInt(s);
  506. },
  507. type: "numeric"
  508. });
  509. $.tablesorter.addParser({
  510. id: "currency",
  511. is: function(s) {
  512. return /^[£$€?.]/.test(s);
  513. },
  514. format: function(s) {
  515. return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));
  516. },
  517. type: "numeric"
  518. });
  519. $.tablesorter.addParser({
  520. id: "integer",
  521. is: function(s) {
  522. return /^\d+$/.test(s);
  523. },
  524. format: function(s) {
  525. return $.tablesorter.formatFloat(s);
  526. },
  527. type: "numeric"
  528. });
  529. $.tablesorter.addParser({
  530. id: "floating",
  531. is: function(s) {
  532. return s.match(new RegExp(/^(\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?$/));
  533. },
  534. format: function(s) {
  535. return $.tablesorter.formatFloat(s.replace(new RegExp(/,/),""));
  536. },
  537. type: "numeric"
  538. });
  539. $.tablesorter.addParser({
  540. id: "ipAddress",
  541. is: function(s) {
  542. return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
  543. },
  544. format: function(s) {
  545. var a = s.split(".");
  546. var r = "";
  547. for (var i = 0, item; item = a[i]; i++) {
  548. if(item.length == 2) {
  549. r += "0" + item;
  550. } else {
  551. r += item;
  552. }
  553. }
  554. return $.tablesorter.formatFloat(s);
  555. },
  556. type: "numeric"
  557. });
  558. $.tablesorter.addParser({
  559. id: "url",
  560. is: function(s) {
  561. return /^(https?|ftp|file):\/\/$/.test(s);
  562. },
  563. format: function(s) {
  564. return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
  565. },
  566. type: "text"
  567. });
  568. $.tablesorter.addParser({
  569. id: "isoDate",
  570. is: function(s) {
  571. return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
  572. },
  573. format: function(s) {
  574. return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),"/")).getTime() : "0");
  575. },
  576. type: "numeric"
  577. });
  578. $.tablesorter.addParser({
  579. id: "percent",
  580. is: function(s) {
  581. return /^\d{1,3}%$/.test(s);
  582. },
  583. format: function(s) {
  584. return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));
  585. },
  586. type: "numeric"
  587. });
  588. $.tablesorter.addParser({
  589. id: "usLongDate",
  590. is: function(s) {
  591. 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);
  592. },
  593. format: function(s) {
  594. return $.tablesorter.formatFloat(new Date(s).getTime());
  595. },
  596. type: "numeric"
  597. });
  598. $.tablesorter.addParser({
  599. id: "shortDate",
  600. is: function(s) {
  601. return /\d{1,2}[\/-]\d{1,2}[\/-]\d{2,4}/.test(s);
  602. },
  603. format: function(s,table) {
  604. var c = table.config;
  605. s = s.replace(new RegExp(/-/g),"/");
  606. if(c.dateFormat == "us") {
  607. /** reformat the string in ISO format */
  608. s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$1/$2");
  609. } else if(c.dateFormat == "uk") {
  610. /** reformat the string in ISO format */
  611. s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$2/$1");
  612. } else if(c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
  613. s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2})/), "$1/$2/$3");
  614. }
  615. return $.tablesorter.formatFloat(new Date(s).getTime());
  616. },
  617. type: "numeric"
  618. });
  619. $.tablesorter.addParser({
  620. id: "time",
  621. is: function(s) {
  622. return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
  623. },
  624. format: function(s) {
  625. return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
  626. },
  627. type: "numeric"
  628. });
  629. $.tablesorter.addParser({
  630. id: "metadata",
  631. is: function(s) {
  632. return false;
  633. },
  634. format: function(s,table,cell) {
  635. var c = table.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
  636. return $(cell).data()[p];
  637. },
  638. type: "numeric"
  639. });
  640. // add default widgets
  641. $.tablesorter.addWidget({
  642. id: "zebra",
  643. format: function(table) {
  644. $("> tbody:first/tr:visible:even",table).removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]);
  645. $("> tbody:first/tr:visible:odd",table).removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);
  646. }
  647. });
  648. })(jQuery);