source: trunk/www.guidonia.net/wp/wp-content/plugins/wordpress-google-seo-positioner/js/jquery.tablesorter.js@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 17.5 KB
Line 
1/*
2 *
3 * TableSorter - Client-side table sorting with ease!
4 *
5 * Copyright (c) 2006 Christian Bach (http://motherrussia.polyester.se)
6 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
7 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
8 *
9 * jQueryDate:
10 * jQueryAuthor: Christian jQuery
11 *
12 */
13(function($) {
14
15 $.fn.tableSorter = function(o) {
16
17 var defaults = {
18 sortDir: 0,
19 sortColumn: null,
20 sortClassAsc: 'ascending',
21 sortClassDesc: 'descending',
22 headerClass: null,
23 stripingRowClass: false,
24 highlightClass: false,
25 rowLimit: 0,
26 minRowsForWaitingMsg: 0,
27 disableHeader: -1,
28 stripeRowsOnStartUp: false,
29 columnParser: false,
30 rowHighlightClass: false,
31 useCache: true,
32 debug: false,
33 textExtraction: 'simple',
34 textExtractionCustom: false,
35 textExtractionType: false,
36 bind: true,
37 addHeaderLink: false,
38 lockedSortDir: false,
39 enableResize: false,
40 dateFormat: 'mm/dd/yyyy' /** us default, uk dd/mm/yyyy */
41 };
42
43 return this.each(function(){
44
45 /** merge default with custom options */
46 $.extend(defaults, o);
47
48 /** Private vars */
49 var COLUMN_DATA; /** array for storing columns */
50 var COLUMN_CACHE; /** array for storing sort caches.*/
51 var COLUMN_INDEX; /** int for storing current cell index */
52 var COLUMN_SORTER_CACHE = []; /** array for sorter parser cache */
53 var COLUMN_CELL; /** stores the current cell object */
54 var COLUMN_DIR; /** stores the current soring direction */
55 var COLUMN_HEADER_LENGTH; /** stores the columns header length */
56 var COLUMN_ROW_LENGTH;
57 var ROW_LAST_HIGHLIGHT_OBJ = false;
58 var COLUMN_LAST_INDEX = -1;
59 var COLUMN_LAST_DIR = defaults.sortDir;
60
61 /** table object holder.*/
62 var oTable = this;
63
64 if(defaults.stripeRowsOnStartUp && defaults.stripingRowClass) {
65 $.tableSorter.utils.stripeRows(defaults,oTable);
66 }
67
68 /** bind events to the tablesorter element */
69 $(this).bind("resort",doSorting);
70
71 $(this).bind("flushCache",function(event) {
72 COLUMN_CACHE = [];
73 });
74
75 $(this).bind("updateColumnData",buildColumnDataIndex);
76
77 /** Store length of table rows. */
78 var tableRowLength = (oTable.tBodies[0] && oTable.tBodies[0].rows.length-1) || 0;
79
80 /** Index column data. */
81 buildColumnDataIndex();
82
83 /** when done, build headers. */
84 buildColumnHeaders();
85
86 function buildColumnHeaders() {
87 var oFirstTableRow = oTable.rows[0];
88 var oDataSampleRow = oTable.rows[1];
89 /** store column length */
90 COLUMN_HEADER_LENGTH = oFirstTableRow.cells.length;
91 /** loop column headers */
92 for( var i=0; i < COLUMN_HEADER_LENGTH; i++ ) {
93 var oCell = oFirstTableRow.cells[i];
94
95 if(oDataSampleRow && !$.tableSorter.utils.isHeaderDisabled(defaults,oCell,defaults.disableHeader,i)) {
96 /** get current cell from columns headers */
97 var oCellValue = $.tableSorter.utils.getElementText(defaults,oDataSampleRow.cells[i],'columns',i);
98 /** check for default column. */
99 if(typeof(defaults.sortColumn) == "string") {
100 if(defaults.sortColumn.toLowerCase() == $.tableSorter.utils.getElementText(defaults,oCell,'header',i).toLowerCase()) {
101 defaults.sortColumn = i;
102 }
103 }
104
105 /** get sorting method for column. */
106 COLUMN_SORTER_CACHE[i] = $.tableSorter.analyzer.analyseString(defaults,oCellValue);
107
108 /** if we have a column parser, set it manual. */
109 if(defaults.columnParser) {
110 var a = defaults.columnParser;
111 var l = a.length;
112 for(var j=0; j < l; j++) {
113 if(i == a[j][0]) {
114 COLUMN_SORTER_CACHE[i] = $.tableSorter.analyzer.getById(a[j][1]);
115 continue;
116 }
117 }
118 }
119
120 if(defaults.headerClass) {
121 $(oCell).addClass(defaults.headerClass);
122 }
123 if(defaults.addHeaderLink) {
124 $(oCell).wrapInner({element: '<a href="#">', name: 'a', className: 'sorter'});
125
126 $(".sorter",oCell).click(function(e) {
127 sortOnColumn( $(this).parent(), ((defaults.lockedSortDir) ? defaults.lockedSortDir : $(this).parent()[0].count++) % 2, $(this).parent()[0].index );
128 return false;
129 });
130 } else {
131 $(oCell).click(function(e) {
132 sortOnColumn( $(this), ((defaults.lockedSortDir) ? defaults.lockedSortDir : $(this)[0].count++) % 2, $(this)[0].index );
133 return false;
134 });
135 }
136 oCell.index = i;
137 oCell.count = 0;
138 }
139 }
140 /** comming feature. */
141 if(defaults.enableResize) {
142 addColGroup(oFirstTableRow);
143 }
144 /** if we have a init sorting, fire it! */
145 if(defaults.sortColumn != null) {
146 $(oFirstTableRow.cells[defaults.sortColumn]).trigger("click");
147 }
148
149 if(defaults.rowHighlightClass) {
150 $("> tbody:first/tr",oTable).click(function() {
151 if(ROW_LAST_HIGHLIGHT_OBJ) {
152 ROW_LAST_HIGHLIGHT_OBJ.removeClass(defaults.rowHighlightClass);
153 }
154 ROW_LAST_HIGHLIGHT_OBJ = $(this).addClass(defaults.rowHighlightClass);
155 });
156 }
157 }
158 /** break out and put i $.tableSorter? */
159 function buildColumnDataIndex() {
160 /** make colum data. */
161 COLUMN_DATA = [];
162 COLUMN_CACHE = [];
163 COLUMN_ROW_LENGTH = (oTable.tBodies[0] && oTable.tBodies[0].rows.length) || 0;
164 var l = COLUMN_ROW_LENGTH;
165 for (var i=0;i < l; i++) {
166 /** Add the table data to main data array */
167 COLUMN_DATA.push(oTable.tBodies[0].rows[i]);
168 }
169 }
170
171 function addColGroup(columnsHeader) {
172 var oSampleTableRow = oTable.rows[1];
173 /** adjust header to the sample rows */
174 for(var i=0; i < COLUMN_HEADER_LENGTH; i++) {
175 if(oSampleTableRow && oSampleTableRow.cells[i])
176 $(columnsHeader.cells[i]).css("width",oSampleTableRow.cells[i].clientWidth + "px");
177 }
178 }
179
180 function sortOnColumn(oCell,dir,index) {
181 /** trigger event sort start. */
182 if(tableRowLength > defaults.minRowsForWaitingMsg) {
183 $(oTable).trigger( "sortStart");
184 }
185 /** define globals for current sorting. */
186 COLUMN_INDEX = index;
187 COLUMN_CELL = oCell;
188 COLUMN_DIR = dir;
189 /** clear all classes, need to be optimized. */
190 $("thead th",oTable).removeClass(defaults.sortClassAsc).removeClass(defaults.sortClassDesc);
191 /**add active class and append image. */
192 $(COLUMN_CELL).addClass((dir % 2 ? defaults.sortClassAsc : defaults.sortClassDesc));
193 /** if this is fired, with a straight call, sortStart / Stop would never be fired. */
194 setTimeout(doSorting,0);
195 }
196
197 function doSorting() {
198 /** added check to see if COLUMN_INDEX is set */
199 if(COLUMN_INDEX >= 0) {
200 /** array for storing sorted data. */
201 var columns;
202 /** sorting exist in cache, get it. */
203 if($.tableSorter.cache.exist(COLUMN_CACHE,COLUMN_INDEX) && defaults.useCache) {
204 /** get from cache */
205 var cache = $.tableSorter.cache.get(COLUMN_CACHE,COLUMN_INDEX);
206 /** figure out the way to sort. */
207 if(cache.dir == COLUMN_DIR) {
208 columns = cache.data;
209 cache.dir = COLUMN_DIR;
210 } else {
211 columns = cache.data.reverse();
212 cache.dir = COLUMN_DIR;
213 }
214 /** sort and cache */
215 } else {
216 /** return flat data, and then sort it. */
217 var flatData = $.tableSorter.data.flatten(defaults,COLUMN_DATA,COLUMN_SORTER_CACHE,COLUMN_INDEX);
218 /** do sorting, only onces per column. */
219 flatData.sort(COLUMN_SORTER_CACHE[COLUMN_INDEX].sorter);
220 /** if we have a sortDir, reverse the damn thing. */
221 if(COLUMN_LAST_DIR != COLUMN_DIR) {
222 flatData.reverse();
223 }
224 /** rebuild data from flat. */
225 columns = $.tableSorter.data.rebuild(COLUMN_DATA,flatData,COLUMN_INDEX,COLUMN_LAST_INDEX);
226 /** append to table cache. */
227 $.tableSorter.cache.add(COLUMN_CACHE,COLUMN_INDEX,COLUMN_DIR,columns);
228 /** good practise */
229 flatData = null;
230 }
231 /** append to table > tbody */
232 $.tableSorter.utils.appendToTable(defaults,oTable,columns,COLUMN_INDEX,COLUMN_LAST_INDEX);
233 /** good practise i guess */
234 columns = null;
235 /** trigger stop event. */
236 if(tableRowLength > defaults.minRowsForWaitingMsg) {
237 $(oTable).trigger("sortStop",[COLUMN_INDEX]);
238 }
239 COLUMN_LAST_INDEX = COLUMN_INDEX;
240 }
241 }
242 });
243 };
244 $.fn.sortStart = function(fn) {
245 return this.bind("sortStart",fn);
246 };
247 $.fn.sortReload = function(fn) {
248 return this.bind("sortStart",fn);
249 };
250 $.fn.sortStop = function(fn) {
251 return this.bind("sortStop",fn);
252 };
253 $.tableSorter = {
254 params: {},
255 /** cache functions, okey for now. */
256 cache: {
257 add: function(cache,index,dir,data) {
258 var oCache = {};
259 oCache.dir = dir;
260 oCache.data = data;
261 cache[index] = oCache;
262 },
263 get: function (cache,index) {
264 return cache[index];
265 },
266 exist: function(cache,index) {
267 var oCache = cache[index];
268 if(!oCache) {
269 return false
270 } else {
271 return true
272 }
273 },
274 clear: function(cache) {
275 cache = [];
276 }
277 },
278 data: {
279 flatten: function(defaults,columnData,columnCache,columnIndex) {
280 var flatData = [];
281 var l = columnData.length;
282 for (var i=0;i < l; i++) {
283 flatData.push([i,columnCache[columnIndex].format($.tableSorter.utils.getElementText(defaults,columnData[i].cells[columnIndex],'columns',columnIndex),defaults)]);
284 }
285 return flatData;
286 },
287 rebuild: function(columnData,flatData,columnIndex,columnLastIndex) {
288 var l = flatData.length;
289 var sortedData = [];
290 for (var i=0;i < l; i++) {
291 sortedData.push(columnData[flatData[i][0]]);
292 }
293 return sortedData;
294 }
295 },
296 sorters: {},
297 parsers: {},
298 analyzer: {
299 analyzers: [],
300 add: function(analyzer) {
301 this.analyzers.push(analyzer);
302 },
303 add_to_front: function(analyzer) {
304 this.analyzers.unshift(analyzer);
305 },
306 analyseString: function(defaults,s) {
307 /** set defaults params. */
308 var found = false;
309 var analyzer = $.tableSorter.parsers.generic;
310 var list = this.analyzers;
311 $.each(list, function(i) {
312 if(!found) {
313 if(list[i].is(s)) {
314 found = true;
315 analyzer = list[i];
316 }
317 }
318 });
319 return analyzer;
320
321 },
322 getById: function(s) {
323 var list = this.analyzers;
324 var analyzer = $.tableSorter.parsers.generic;
325 $.each(list, function(i) {
326 if(list[i].id == s) {
327 analyzer = list[i];
328 }
329 });
330 return analyzer;
331 }
332 },
333 utils: {
334 getElementText: function(defaults,o,type,index) {
335 if(!o) return "";
336 var elementText = "";
337 if(type == 'header') {
338 elementText = $(o).text();
339 } else if(type == 'columns') {
340 if(defaults.textExtractionCustom && typeof(defaults.textExtractionCustom[index]) == "function") {
341 elementText = defaults.textExtractionCustom[index](o);
342 } else {
343 if(defaults.textExtraction == 'simple') {
344 if(typeof(defaults.textExtractionType) == "object") {
345 var d = defaults.textExtractionType;
346 $.each(d,function(i) {
347 var val = o[d[i]];
348 if(val && val.length > 0) {
349 elementText = val;
350 }
351 });
352 } else {
353 if(o.childNodes[0] && o.childNodes[0].hasChildNodes()) {
354 elementText = o.childNodes[0].innerHTML;
355 } else {
356 elementText = o.innerHTML;
357 }
358 }
359 } else if(defaults.textExtraction == 'complex') {
360 // make a jquery object, this will take forever with large tables.
361 elementText = $(o).text();
362 }
363 }
364 }
365 return elementText;
366 },
367 formatFloat: function(s) {
368 var i = parseFloat(s);
369 return (isNaN(i)) ? 0 : i;
370 },
371 appendToTable: function(defaults,o,c,index,lastIndex) {
372 var l = c.length;
373 $("> tbody:first",o).empty().append(c);
374 /** jquery way, need to be benched mark! */
375 if(defaults.stripingRowClass) {
376 /** remove old! */
377 $("> tbody:first/tr",o).removeClass(defaults.stripingRowClass[0]).removeClass(defaults.stripingRowClass[1]);
378 /** add new! */
379 $.tableSorter.utils.stripeRows(defaults,o);
380 }
381 if(defaults.highlightClass) {
382 $.tableSorter.utils.highlightColumn(defaults,o,index,lastIndex);
383 }
384
385 /** empty object, good practice! */
386 c=null;
387 },
388 highlightColumn : function(defaults,o,index, lastIndex) {
389 $("> tbody:first/tr", o).find("td:eq(" + lastIndex+ ")").removeClass(defaults.highlightClass);
390 $("> tbody:first/tr", o).find("td:eq(" + index + ")").addClass(defaults.highlightClass);
391 },
392 stripeRows: function(defaults,o) {
393 $("> tbody:first/tr:visible:even",o).addClass(defaults.stripingRowClass[0]);
394 $("> tbody:first/tr:visible:odd",o).addClass(defaults.stripingRowClass[1]);
395 },
396 isHeaderDisabled: function(defaults,o,arg,index) {
397 if(typeof(arg) == "number") {
398 return (arg == index)? true : false;
399 } else if(typeof(arg) == "string") {
400 return (arg.toLowerCase() == $.tableSorter.utils.getElementText(defaults,o,'header',index).toLowerCase()) ? true : false;
401 } else if(arg.parentNode) {
402 return (o == arg) ? true : false
403 } else if(typeof(arg) == "object") {
404 var l = arg.length;
405 if(!this.lastFound) { this.lastFound = -1; }
406 for(var i=0; i < l; i++) {
407 var val = $.tableSorter.utils.isHeaderDisabled(defaults,o,arg[i],index);
408 if(this.lastFound != i && val) {
409 this.lastFound = i;
410 return val;
411 }
412 }
413 } else {
414 return false
415 }
416 }
417 },
418 sorters: {
419 generic: function(a,b) {
420 return ((a[1] < b[1]) ? -1 : ((a[1] > b[1]) ? 1 : 0));
421 },
422 numeric: function(a,b) {
423 return a[1]-b[1];
424 }
425 }
426 };
427 $.tableSorter.parsers.generic = {
428 id: 'generic',
429 is: function(s) {
430 return true;
431 },
432 format: function(s) {
433 return jQuery.trim(s.toLowerCase());
434 },
435 sorter: $.tableSorter.sorters.generic
436 };
437 $.tableSorter.parsers.currency = {
438 id: 'currency',
439 is: function(s) {
440 return s.match(new RegExp(/^[£$?.]/g));
441 },
442 format: function(s) {
443 return $.tableSorter.utils.formatFloat(s.replace(new RegExp(/[^0-9.]/g),''));
444 },
445 sorter: $.tableSorter.sorters.numeric
446 };
447 $.tableSorter.parsers.integer = {
448 id: 'integer',
449 is: function(s) {
450 return s.match(new RegExp(/^\d+$/));
451 },
452 format: function(s) {
453 return $.tableSorter.utils.formatFloat(s);
454 },
455 sorter: $.tableSorter.sorters.numeric
456 };
457 $.tableSorter.parsers.floating = {
458 id: 'floating',
459 is: function(s) {
460 return s.match(new RegExp(/^(\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?$/));
461 },
462 format: function(s) {
463 return $.tableSorter.utils.formatFloat(s.replace(new RegExp(/,/),''));
464 },
465 sorter: $.tableSorter.sorters.numeric
466 };
467 $.tableSorter.parsers.ipAddress = {
468 id: 'ipAddress',
469 is: function(s) {
470 return s.match(/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/);
471 },
472 format: function(s) {
473 var a = s.split('.');
474 var r = '';
475 for (var i = 0, item; item = a[i]; i++) {
476 if(item.length == 2) {
477 r += '0' + item;
478 } else {
479 r += item;
480 }
481 }
482 return $.tableSorter.utils.formatFloat(r);
483 },
484 sorter: $.tableSorter.sorters.numeric
485 };
486 $.tableSorter.parsers.url = {
487 id: 'url',
488 is: function(s) {
489 return s.match(new RegExp(/(https?|ftp|file):\/\//));
490 },
491 format: function(s) {
492 return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
493 },
494 sorter: $.tableSorter.sorters.generic
495 };
496 $.tableSorter.parsers.isoDate = {
497 id: 'isoDate',
498 is: function(s) {
499 return s.match(new RegExp(/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/));
500 },
501 format: function(s) {
502 return parseFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),'/')).getTime() : "0");
503 },
504 sorter: $.tableSorter.sorters.numeric
505 };
506 $.tableSorter.parsers.usLongDate = {
507 id: 'usLongDate',
508 is: function(s) {
509 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)))$/));
510 },
511 format: function(s) {
512 return $.tableSorter.utils.formatFloat((new Date(s)).getTime());
513 },
514 sorter: $.tableSorter.sorters.numeric
515 };
516 $.tableSorter.parsers.shortDate = {
517 id: 'shortDate',
518 is: function(s) {
519 return s.match(new RegExp(/\d{1,2}[\/-]\d{1,2}[\/-]\d{2,4}/));
520 },
521 format: function(s,defaults) {
522 s = s.replace(new RegExp(/-/g),'/');
523 if(defaults.dateFormat == "mm/dd/yyyy" || defaults.dateFormat == "mm-dd-yyyy") {
524 /** reformat the string in ISO format */
525 s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), '$3/$1/$2');
526 } else if(defaults.dateFormat == "dd/mm/yyyy" || defaults.dateFormat == "dd-mm-yyyy") {
527 /** reformat the string in ISO format */
528 s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), '$3/$2/$1');
529 } else if(defaults.dateFormat == "dd/mm/yy" || defaults.dateFormat == "dd-mm-yy") {
530 s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2})/), '$1/$2/$3');
531 }
532 return $.tableSorter.utils.formatFloat((new Date(s)).getTime());
533 },
534 sorter: $.tableSorter.sorters.numeric
535 };
536 $.tableSorter.parsers.time = {
537 id: 'time',
538 is: function(s) {
539 return s.toUpperCase().match(new RegExp(/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
540 },
541 format: function(s) {
542 return $.tableSorter.utils.formatFloat((new Date("2000/01/01 " + s)).getTime());
543 },
544 sorter: $.tableSorter.sorters.numeric
545 };
546 /** add parsers */
547 $.tableSorter.analyzer.add($.tableSorter.parsers.currency);
548 $.tableSorter.analyzer.add($.tableSorter.parsers.integer);
549 $.tableSorter.analyzer.add($.tableSorter.parsers.isoDate);
550 $.tableSorter.analyzer.add($.tableSorter.parsers.shortDate);
551 $.tableSorter.analyzer.add($.tableSorter.parsers.usLongDate);
552 $.tableSorter.analyzer.add($.tableSorter.parsers.ipAddress);
553 $.tableSorter.analyzer.add($.tableSorter.parsers.url);
554 $.tableSorter.analyzer.add($.tableSorter.parsers.time);
555 $.tableSorter.analyzer.add($.tableSorter.parsers.floating);
556
557})(jQuery);
Note: See TracBrowser for help on using the repository browser.