source: extensions/nbc_ThemeChanger/include/jquery.tablesorter.js @ 17044

Last change on this file since 17044 was 10161, checked in by datajulien, 13 years ago

nbc_ThemeChanger_admin

Piwigo 2.2 compatibility upgrade

url rewrite for modification and suppression actions.

Update in version 2.0.5b of jquery.tablesorter plugin and correction of the autosort js bug when the table is empty

Modified files:

main.inc.php
admin/nbc_themeChanger_admin.tpl
admin/nbc_themeChanger_admin.php
include/jquery.tablesorter.js

File size: 40.3 KB
Line 
1/*
2 *
3 * TableSorter 2.0 - Client-side table sorting with ease!
4 * Version 2.0.5b-jqz WARNING Modified version specific for Piwigo nbc_ThemeChanger plugin
5 * @requires jQuery v1.2.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 column headers.
23 *
24 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
25 *         
26 * @desc Create a tablesorter interface and disableing the first and second  column headers.
27 *     
28 *
29 * @example $('table').tablesorter({ headers: { 0: {sorter:"integer"}, 1: {sorter:"currency"} } });
30 *
31 * @desc Create a tablesorter interface and set a column parser for the first
32 *       and second column.
33 *
34 *
35 * @param Object
36 *            settings An object literal containing key/value pairs to provide
37 *            optional settings.
38 *
39 *
40 * @option String cssHeader (optional) A string of the class name to be appended
41 *         to sortable tr elements in the thead of the table. Default value:
42 *         "header"
43 *
44 * @option String cssAsc (optional) A string of the class name to be appended to
45 *         sortable tr elements in the thead on a ascending sort. Default value:
46 *         "headerSortUp"
47 *
48 * @option String cssDesc (optional) A string of the class name to be appended
49 *         to sortable tr elements in the thead on a descending sort. Default
50 *         value: "headerSortDown"
51 *
52 * @option String sortInitialOrder (optional) A string of the inital sorting
53 *         order can be asc or desc. Default value: "asc"
54 *
55 * @option String sortMultisortKey (optional) A string of the multi-column sort
56 *         key. Default value: "shiftKey"
57 *
58 * @option String textExtraction (optional) A string of the text-extraction
59 *         method to use. For complex html structures inside td cell set this
60 *         option to "complex", on large tables the complex option can be slow.
61 *         Default value: "simple"
62 *
63 * @option Object headers (optional) An array containing the forces sorting
64 *         rules. This option let's you specify a default sorting rule. Default
65 *         value: null
66 *
67 * @option Array sortList (optional) An array containing the forces sorting
68 *         rules. This option let's you specify a default sorting rule. Default
69 *         value: null
70 *
71 * @option Array sortForce (optional) An array containing forced sorting rules.
72 *         This option let's you specify a default sorting rule, which is
73 *         prepended to user-selected rules. Default value: null
74 *
75 * @option Boolean sortLocaleCompare (optional) Boolean flag indicating whatever
76 *         to use String.localeCampare method or not. Default set to true.
77 *
78 *
79 * @option Array sortAppend (optional) An array containing forced sorting rules.
80 *         This option let's you specify a default sorting rule, which is
81 *         appended to user-selected rules. Default value: null
82 *
83 * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter
84 *         should apply fixed widths to the table columns. This is usefull when
85 *         using the pager companion plugin. This options requires the dimension
86 *         jquery plugin. Default value: false
87 *
88 * @option Boolean cancelSelection (optional) Boolean flag indicating if
89 *         tablesorter should cancel selection of the table headers text.
90 *         Default value: true
91 *
92 * @option Boolean debug (optional) Boolean flag indicating if tablesorter
93 *         should display debuging information usefull for development.
94 *
95 * @type jQuery
96 *
97 * @name tablesorter
98 *
99 * @cat Plugins/Tablesorter
100 *
101 * @author Christian Bach/christian.bach@polyester.se
102 */
103
104(function ($) {
105    $.extend({
106        tablesorter: new
107        function () {
108
109            var parsers = [],
110                widgets = [];
111
112            this.defaults = {
113                cssHeader: "header",
114                cssAsc: "headerSortUp",
115                cssDesc: "headerSortDown",
116                cssChildRow: "expand-child",
117                sortInitialOrder: "asc",
118                sortMultiSortKey: "shiftKey",
119                sortForce: null,
120                sortAppend: null,
121                sortLocaleCompare: true,
122                textExtraction: "simple",
123                parsers: {}, widgets: [],
124                widgetZebra: {
125                    css: ["even", "odd"]
126                }, headers: {}, widthFixed: false,
127                cancelSelection: true,
128                sortList: [],
129                headerList: [],
130                dateFormat: "us",
131                decimal: '/\.|\,/g',
132                onRenderHeader: null,
133                selectorHeaders: 'thead th',
134                debug: false
135            };
136
137            /* debuging utils */
138
139            function benchmark(s, d) {
140                log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
141            }
142
143            this.benchmark = benchmark;
144
145            function log(s) {
146                if (typeof console != "undefined" && typeof console.debug != "undefined") {
147                    console.log(s);
148                } else {
149                    alert(s);
150                }
151            }
152
153            /* parsers utils */
154
155            function buildParserCache(table, $headers) {
156
157                if (table.config.debug) {
158                    var parsersDebug = "";
159                }
160
161                if (table.tBodies.length == 0) return; // In the case of empty tables
162                var rows = table.tBodies[0].rows;
163
164                if (rows[0]) {
165
166                    var list = [],
167                        cells = rows[0].cells,
168                        l = cells.length;
169
170                    for (var i = 0; i < l; i++) {
171
172                        var p = false;
173
174                        if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) {
175
176                            p = getParserById($($headers[i]).metadata().sorter);
177
178                        } else if ((table.config.headers[i] && table.config.headers[i].sorter)) {
179
180                            p = getParserById(table.config.headers[i].sorter);
181                        }
182                        if (!p) {
183
184                            p = detectParserForColumn(table, rows, -1, i);
185                        }
186
187                        if (table.config.debug) {
188                            parsersDebug += "column:" + i + " parser:" + p.id + "\n";
189                        }
190
191                        list.push(p);
192                    }
193                }
194
195                if (table.config.debug) {
196                    log(parsersDebug);
197                }
198
199                return list;
200            };
201
202            function detectParserForColumn(table, rows, rowIndex, cellIndex) {
203                var l = parsers.length,
204                    node = false,
205                    nodeValue = false,
206                    keepLooking = true;
207                while (nodeValue == '' && keepLooking) {
208                    rowIndex++;
209                    if (rows[rowIndex]) {
210                        node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex);
211                        nodeValue = trimAndGetNodeText(table.config, node);
212                        if (table.config.debug) {
213                            log('Checking if value was empty on row:' + rowIndex);
214                        }
215                    } else {
216                        keepLooking = false;
217                    }
218                }
219                for (var i = 1; i < l; i++) {
220                    if (parsers[i].is(nodeValue, table, node)) {
221                        return parsers[i];
222                    }
223                }
224                // 0 is always the generic parser (text)
225                return parsers[0];
226            }
227
228            function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) {
229                return rows[rowIndex].cells[cellIndex];
230            }
231
232            function trimAndGetNodeText(config, node) {
233                return $.trim(getElementText(config, node));
234            }
235
236            function getParserById(name) {
237                var l = parsers.length;
238                for (var i = 0; i < l; i++) {
239                    if (parsers[i].id.toLowerCase() == name.toLowerCase()) {
240                        return parsers[i];
241                    }
242                }
243                return false;
244            }
245
246            /* utils */
247
248            function buildCache(table) {
249
250                if (table.config.debug) {
251                    var cacheTime = new Date();
252                }
253                       
254                        // Check the column exists - jqz
255                                if (table.tBodies[0].rows.length < 1) {
256                                return;}                               
257                var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
258                    totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
259                    parsers = table.config.parsers,
260                    cache = {
261                        row: [],
262                        normalized: []
263                    };
264
265                for (var i = 0; i < totalRows; ++i) {
266
267                    /** Add the table data to main data array */
268                    var c = $(table.tBodies[0].rows[i]),
269                        cols = [];
270
271                    // if this is a child row, add it to the last row's children and
272                    // continue to the next row
273                    if (c.hasClass(table.config.cssChildRow)) {
274                        cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
275                        // go to the next for loop
276                        continue;
277                    }
278
279                    cache.row.push(c);
280
281                    for (var j = 0; j < totalCells; ++j) {
282                        cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j]));
283                    }
284
285                    cols.push(cache.normalized.length); // add position for rowCache
286                    cache.normalized.push(cols);
287                    cols = null;
288                };
289
290                if (table.config.debug) {
291                    benchmark("Building cache for " + totalRows + " rows:", cacheTime);
292                }
293
294                return cache;
295            };
296
297            function getElementText(config, node) {
298
299                var text = "";
300
301                if (!node) return "";
302
303                if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false;
304
305                if (config.textExtraction == "simple") {
306                    if (config.supportsTextContent) {
307                        text = node.textContent;
308                    } else {
309                        if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
310                            text = node.childNodes[0].innerHTML;
311                        } else {
312                            text = node.innerHTML;
313                        }
314                    }
315                } else {
316                    if (typeof(config.textExtraction) == "function") {
317                        text = config.textExtraction(node);
318                    } else {
319                        text = $(node).text();
320                    }
321                }
322                return text;
323            }
324
325            function appendToTable(table, cache) {
326
327                if (table.config.debug) {
328                    var appendTime = new Date()
329                }
330                               
331                                // Check the column exists - jqz
332                                if (table.tBodies[0].rows.length < 1) {
333                                return;} 
334                               
335                var c = cache,
336                    r = c.row,
337                    n = c.normalized,
338                    totalRows = n.length,
339                    checkCell = (n[0].length - 1),
340                    tableBody = $(table.tBodies[0]),
341                    rows = [];
342
343
344                for (var i = 0; i < totalRows; i++) {
345                    var pos = n[i][checkCell];
346
347                    rows.push(r[pos]);
348
349                    if (!table.config.appender) {
350
351                        //var o = ;
352                        var l = r[pos].length;
353                        for (var j = 0; j < l; j++) {
354                            tableBody[0].appendChild(r[pos][j]);
355                        }
356
357                        //
358                    }
359                }
360
361
362
363                if (table.config.appender) {
364
365                    table.config.appender(table, rows);
366                }
367
368                rows = null;
369
370                if (table.config.debug) {
371                    benchmark("Rebuilt table:", appendTime);
372                }
373
374                // apply table widgets
375                applyWidget(table);
376
377                // trigger sortend
378                setTimeout(function () {
379                    $(table).trigger("sortEnd");
380                }, 0);
381
382            };
383
384            function buildHeaders(table) {
385
386                if (table.config.debug) {
387                    var time = new Date();
388                }
389
390                var meta = ($.metadata) ? true : false;
391               
392                var header_index = computeTableHeaderCellIndexes(table);
393
394                $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) {
395
396                    this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
397                    // this.column = index;
398                    this.order = formatSortingOrder(table.config.sortInitialOrder);
399                   
400                                       
401                                        this.count = this.order;
402
403                    if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true;
404                                        if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index);
405
406                    if (!this.sortDisabled) {
407                        var $th = $(this).addClass(table.config.cssHeader);
408                        if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th);
409                    }
410
411                    // add cell to headerList
412                    table.config.headerList[index] = this;
413                });
414
415                if (table.config.debug) {
416                    benchmark("Built headers:", time);
417                    log($tableHeaders);
418                }
419
420                return $tableHeaders;
421
422            };
423
424            // from:
425            // http://www.javascripttoolbox.com/lib/table/examples.php
426            // http://www.javascripttoolbox.com/temp/table_cellindex.html
427
428
429            function computeTableHeaderCellIndexes(t) {
430                var matrix = [];
431                var lookup = {};
432                var thead = t.getElementsByTagName('THEAD')[0];
433                var trs = thead.getElementsByTagName('TR');
434
435                for (var i = 0; i < trs.length; i++) {
436                    var cells = trs[i].cells;
437                    for (var j = 0; j < cells.length; j++) {
438                        var c = cells[j];
439
440                        var rowIndex = c.parentNode.rowIndex;
441                        var cellId = rowIndex + "-" + c.cellIndex;
442                        var rowSpan = c.rowSpan || 1;
443                        var colSpan = c.colSpan || 1
444                        var firstAvailCol;
445                        if (typeof(matrix[rowIndex]) == "undefined") {
446                            matrix[rowIndex] = [];
447                        }
448                        // Find first available column in the first row
449                        for (var k = 0; k < matrix[rowIndex].length + 1; k++) {
450                            if (typeof(matrix[rowIndex][k]) == "undefined") {
451                                firstAvailCol = k;
452                                break;
453                            }
454                        }
455                        lookup[cellId] = firstAvailCol;
456                        for (var k = rowIndex; k < rowIndex + rowSpan; k++) {
457                            if (typeof(matrix[k]) == "undefined") {
458                                matrix[k] = [];
459                            }
460                            var matrixrow = matrix[k];
461                            for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
462                                matrixrow[l] = "x";
463                            }
464                        }
465                    }
466                }
467                return lookup;
468            }
469
470            function checkCellColSpan(table, rows, row) {
471                var arr = [],
472                    r = table.tHead.rows,
473                    c = r[row].cells;
474
475                for (var i = 0; i < c.length; i++) {
476                    var cell = c[i];
477
478                    if (cell.colSpan > 1) {
479                        arr = arr.concat(checkCellColSpan(table, headerArr, row++));
480                    } else {
481                        if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) {
482                            arr.push(cell);
483                        }
484                        // headerArr[row] = (i+row);
485                    }
486                }
487                return arr;
488            };
489
490            function checkHeaderMetadata(cell) {
491                if (($.metadata) && ($(cell).metadata().sorter === false)) {
492                    return true;
493                };
494                return false;
495            }
496
497            function checkHeaderOptions(table, i) {
498                if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) {
499                    return true;
500                };
501                return false;
502            }
503                       
504                         function checkHeaderOptionsSortingLocked(table, i) {
505                if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder;
506                return false;
507            }
508                       
509            function applyWidget(table) {
510                var c = table.config.widgets;
511                var l = c.length;
512                for (var i = 0; i < l; i++) {
513
514                    getWidgetById(c[i]).format(table);
515                }
516
517            }
518
519            function getWidgetById(name) {
520                var l = widgets.length;
521                for (var i = 0; i < l; i++) {
522                    if (widgets[i].id.toLowerCase() == name.toLowerCase()) {
523                        return widgets[i];
524                    }
525                }
526            };
527
528            function formatSortingOrder(v) {
529                if (typeof(v) != "Number") {
530                    return (v.toLowerCase() == "desc") ? 1 : 0;
531                } else {
532                    return (v == 1) ? 1 : 0;
533                }
534            }
535
536            function isValueInArray(v, a) {
537                var l = a.length;
538                for (var i = 0; i < l; i++) {
539                    if (a[i][0] == v) {
540                        return true;
541                    }
542                }
543                return false;
544            }
545
546            function setHeadersCss(table, $headers, list, css) {
547                // remove all header information
548                $headers.removeClass(css[0]).removeClass(css[1]);
549
550                var h = [];
551                $headers.each(function (offset) {
552                    if (!this.sortDisabled) {
553                        h[this.column] = $(this);
554                    }
555                });
556
557                var l = list.length;
558                for (var i = 0; i < l; i++) {
559                    h[list[i][0]].addClass(css[list[i][1]]);
560                }
561            }
562
563            function fixColumnWidth(table, $headers) {
564                var c = table.config;
565                if (c.widthFixed) {
566                    var colgroup = $('<colgroup>');
567                    $("tr:first td", table.tBodies[0]).each(function () {
568                        colgroup.append($('<col>').css('width', $(this).width()));
569                    });
570                    $(table).prepend(colgroup);
571                };
572            }
573
574            function updateHeaderSortCount(table, sortList) {
575                var c = table.config,
576                    l = sortList.length;
577                for (var i = 0; i < l; i++) {
578                    var s = sortList[i],
579                        o = c.headerList[s[0]];
580                    o.count = s[1];
581                    o.count++;
582                }
583            }
584
585            /* sorting methods */
586
587            function multisort(table, sortList, cache) {
588
589                if (table.config.debug) {
590                    var sortTime = new Date();
591                }
592                var dynamicExp = "var sortWrapper = function(a,b) {",
593                    l = sortList.length;
594
595                // TODO: inline functions.
596                for (var i = 0; i < l; i++) {
597                               
598                                // Check the column exists - jqz
599                                if (table.tBodies[0].rows.length < 1) {
600                                return;}
601                    var c = sortList[i][0];
602                    var order = sortList[i][1];
603                    // var s = (getCachedSortType(table.config.parsers,c) == "text") ?
604                    // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ?
605                    // "sortNumeric" : "sortNumericDesc");
606                    // var s = (table.config.parsers[c].type == "text") ? ((order == 0)
607                    // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ?
608                    // makeSortNumeric(c) : makeSortNumericDesc(c));
609                    var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c));
610                    var e = "e" + i;
611
612                    dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c
613                    // + "]); ";
614                    dynamicExp += "if(" + e + ") { return " + e + "; } ";
615                    dynamicExp += "else { ";
616
617                }
618
619                // if value is the same keep orignal order
620                var orgOrderCol = cache.normalized[0].length - 1;
621                dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
622
623                for (var i = 0; i < l; i++) {
624                    dynamicExp += "}; ";
625                }
626
627                dynamicExp += "return 0; ";
628                dynamicExp += "}; ";
629
630                if (table.config.debug) {
631                    benchmark("Evaling expression:" + dynamicExp, new Date());
632                }
633
634                eval(dynamicExp);
635
636                cache.normalized.sort(sortWrapper);
637
638                if (table.config.debug) {
639                    benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime);
640                }
641
642                return cache;
643            };
644
645            function makeSortFunction(type, direction, index) {
646                var a = "a[" + index + "]",
647                    b = "b[" + index + "]";
648                if (type == 'text' && direction == 'asc') {
649                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));";
650                } else if (type == 'text' && direction == 'desc') {
651                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));";
652                } else if (type == 'numeric' && direction == 'asc') {
653                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));";
654                } else if (type == 'numeric' && direction == 'desc') {
655                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));";
656                }
657            };
658
659            function makeSortText(i) {
660                return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
661            };
662
663            function makeSortTextDesc(i) {
664                return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
665            };
666
667            function makeSortNumeric(i) {
668                return "a[" + i + "]-b[" + i + "];";
669            };
670
671            function makeSortNumericDesc(i) {
672                return "b[" + i + "]-a[" + i + "];";
673            };
674
675            function sortText(a, b) {
676                if (table.config.sortLocaleCompare) return a.localeCompare(b);
677                return ((a < b) ? -1 : ((a > b) ? 1 : 0));
678            };
679
680            function sortTextDesc(a, b) {
681                if (table.config.sortLocaleCompare) return b.localeCompare(a);
682                return ((b < a) ? -1 : ((b > a) ? 1 : 0));
683            };
684
685            function sortNumeric(a, b) {
686                return a - b;
687            };
688
689            function sortNumericDesc(a, b) {
690                return b - a;
691            };
692
693            function getCachedSortType(parsers, i) {
694                return parsers[i].type;
695            }; /* public methods */
696            this.construct = function (settings) {
697                return this.each(function () {
698                    // if no thead or tbody quit.
699                    if (!this.tHead || !this.tBodies) return;
700                    // declare
701                    var $this, $document, $headers, cache, config, shiftDown = 0,
702                        sortOrder;
703                    // new blank config object
704                    this.config = {};
705                    // merge and extend.
706                    config = $.extend(this.config, $.tablesorter.defaults, settings);
707                    // store common expression for speed
708                    $this = $(this);
709                    // save the settings where they read
710                    $.data(this, "tablesorter", config);
711                    // build headers
712                    $headers = buildHeaders(this);
713                    // try to auto detect column type, and store in tables config
714                    this.config.parsers = buildParserCache(this, $headers);
715                    // build the cache for the tbody cells
716                    cache = buildCache(this);
717                    // get the css class names, could be done else where.
718                    var sortCSS = [config.cssDesc, config.cssAsc];
719                    // fixate columns if the users supplies the fixedWidth option
720                    fixColumnWidth(this);
721                    // apply event handling to headers
722                    // this is to big, perhaps break it out?
723                    $headers.click(
724
725                    function (e) {
726                        var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
727                        if (!this.sortDisabled && totalRows > 0) {
728                            // Only call sortStart if sorting is
729                            // enabled.
730                            $this.trigger("sortStart");
731                            // store exp, for speed
732                            var $cell = $(this);
733                            // get current column index
734                            var i = this.column;
735                            // get current column sort order
736                            this.order = this.count++ % 2;
737                                                        // always sort on the locked order.
738                                                        if(this.lockedOrder) this.order = this.lockedOrder;
739                                                       
740                                                        // user only whants to sort on one
741                            // column
742                            if (!e[config.sortMultiSortKey]) {
743                                // flush the sort list
744                                config.sortList = [];
745                                if (config.sortForce != null) {
746                                    var a = config.sortForce;
747                                    for (var j = 0; j < a.length; j++) {
748                                        if (a[j][0] != i) {
749                                            config.sortList.push(a[j]);
750                                        }
751                                    }
752                                }
753                                // add column to sort list
754                                config.sortList.push([i, this.order]);
755                                // multi column sorting
756                            } else {
757                                // the user has clicked on an all
758                                // ready sortet column.
759                                if (isValueInArray(i, config.sortList)) {
760                                    // revers the sorting direction
761                                    // for all tables.
762                                    for (var j = 0; j < config.sortList.length; j++) {
763                                        var s = config.sortList[j],
764                                            o = config.headerList[s[0]];
765                                        if (s[0] == i) {
766                                            o.count = s[1];
767                                            o.count++;
768                                            s[1] = o.count % 2;
769                                        }
770                                    }
771                                } else {
772                                    // add column to sort list array
773                                    config.sortList.push([i, this.order]);
774                                }
775                            };
776                            setTimeout(function () {
777                                // set css for headers
778                                setHeadersCss($this[0], $headers, config.sortList, sortCSS);
779                                appendToTable(
780                                        $this[0], multisort(
781                                        $this[0], config.sortList, cache)
782                                                                );
783                            }, 1);
784                            // stop normal event by returning false
785                            return false;
786                        }
787                        // cancel selection
788                    }).mousedown(function () {
789                        if (config.cancelSelection) {
790                            this.onselectstart = function () {
791                                return false
792                            };
793                            return false;
794                        }
795                    });
796                    // apply easy methods that trigger binded events
797                    $this.bind("update", function () {
798                        var me = this;
799                        setTimeout(function () {
800                            // rebuild parsers.
801                            me.config.parsers = buildParserCache(
802                            me, $headers);
803                            // rebuild the cache map
804                            cache = buildCache(me);
805                        }, 1);
806                    }).bind("updateCell", function (e, cell) {
807                        var config = this.config;
808                        // get position from the dom.
809                        var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex];
810                        // update cache
811                        cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(
812                        getElementText(config, cell), cell);
813                    }).bind("sorton", function (e, list) {
814                        $(this).trigger("sortStart");
815                        config.sortList = list;
816                        // update and store the sortlist
817                        var sortList = config.sortList;
818                        // update header count index
819                        updateHeaderSortCount(this, sortList);
820                        // set css for headers
821                        setHeadersCss(this, $headers, sortList, sortCSS);
822                        // sort the table and append it to the dom
823                        appendToTable(this, multisort(this, sortList, cache));
824                    }).bind("appendCache", function () {
825                        appendToTable(this, cache);
826                    }).bind("applyWidgetId", function (e, id) {
827                        getWidgetById(id).format(this);
828                    }).bind("applyWidgets", function () {
829                        // apply widgets
830                        applyWidget(this);
831                    });
832                    if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
833                        config.sortList = $(this).metadata().sortlist;
834                    }
835                    // if user has supplied a sort list to constructor.
836                    if (config.sortList.length > 0) {
837                        $this.trigger("sorton", [config.sortList]);
838                    }
839                    // apply widgets
840                    applyWidget(this);
841                });
842            };
843            this.addParser = function (parser) {
844                var l = parsers.length,
845                    a = true;
846                for (var i = 0; i < l; i++) {
847                    if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
848                        a = false;
849                    }
850                }
851                if (a) {
852                    parsers.push(parser);
853                };
854            };
855            this.addWidget = function (widget) {
856                widgets.push(widget);
857            };
858            this.formatFloat = function (s) {
859                var i = parseFloat(s);
860                return (isNaN(i)) ? 0 : i;
861            };
862            this.formatInt = function (s) {
863                var i = parseInt(s);
864                return (isNaN(i)) ? 0 : i;
865            };
866            this.isDigit = function (s, config) {
867                // replace all an wanted chars and match.
868                return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, '')));
869            };
870            this.clearTableBody = function (table) {
871                if ($.browser.msie) {
872                    function empty() {
873                        while (this.firstChild)
874                        this.removeChild(this.firstChild);
875                    }
876                    empty.apply(table.tBodies[0]);
877                } else {
878                    table.tBodies[0].innerHTML = "";
879                }
880            };
881        }
882    });
883
884    // extend plugin scope
885    $.fn.extend({
886        tablesorter: $.tablesorter.construct
887    });
888
889    // make shortcut
890    var ts = $.tablesorter;
891
892    // add default parsers
893    ts.addParser({
894        id: "text",
895        is: function (s) {
896            return true;
897        }, format: function (s) {
898            return $.trim(s.toLocaleLowerCase());
899        }, type: "text"
900    });
901
902    ts.addParser({
903        id: "digit",
904        is: function (s, table) {
905            var c = table.config;
906            return $.tablesorter.isDigit(s, c);
907        }, format: function (s) {
908            return $.tablesorter.formatFloat(s);
909        }, type: "numeric"
910    });
911
912    ts.addParser({
913        id: "currency",
914        is: function (s) {
915            return /^[£$€?.]/.test(s);
916        }, format: function (s) {
917            return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), ""));
918        }, type: "numeric"
919    });
920
921    ts.addParser({
922        id: "ipAddress",
923        is: function (s) {
924            return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
925        }, format: function (s) {
926            var a = s.split("."),
927                r = "",
928                l = a.length;
929            for (var i = 0; i < l; i++) {
930                var item = a[i];
931                if (item.length == 2) {
932                    r += "0" + item;
933                } else {
934                    r += item;
935                }
936            }
937            return $.tablesorter.formatFloat(r);
938        }, type: "numeric"
939    });
940
941    ts.addParser({
942        id: "url",
943        is: function (s) {
944            return /^(https?|ftp|file):\/\/$/.test(s);
945        }, format: function (s) {
946            return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), ''));
947        }, type: "text"
948    });
949
950    ts.addParser({
951        id: "isoDate",
952        is: function (s) {
953            return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
954        }, format: function (s) {
955            return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(
956            new RegExp(/-/g), "/")).getTime() : "0");
957        }, type: "numeric"
958    });
959
960    ts.addParser({
961        id: "percent",
962        is: function (s) {
963            return /\%$/.test($.trim(s));
964        }, format: function (s) {
965            return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), ""));
966        }, type: "numeric"
967    });
968
969    ts.addParser({
970        id: "usLongDate",
971        is: function (s) {
972            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)))$/));
973        }, format: function (s) {
974            return $.tablesorter.formatFloat(new Date(s).getTime());
975        }, type: "numeric"
976    });
977
978    ts.addParser({
979        id: "shortDate",
980        is: function (s) {
981            return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
982        }, format: function (s, table) {
983            var c = table.config;
984            s = s.replace(/\-/g, "/");
985            if (c.dateFormat == "us") {
986                // reformat the string in ISO format
987                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
988            } else if (c.dateFormat == "uk") {
989                // reformat the string in ISO format
990                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
991            } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
992                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
993            }
994            return $.tablesorter.formatFloat(new Date(s).getTime());
995        }, type: "numeric"
996    });
997    ts.addParser({
998        id: "time",
999        is: function (s) {
1000            return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
1001        }, format: function (s) {
1002            return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
1003        }, type: "numeric"
1004    });
1005    ts.addParser({
1006        id: "metadata",
1007        is: function (s) {
1008            return false;
1009        }, format: function (s, table, cell) {
1010            var c = table.config,
1011                p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
1012            return $(cell).metadata()[p];
1013        }, type: "numeric"
1014    });
1015    // add default widgets
1016    ts.addWidget({
1017        id: "zebra",
1018        format: function (table) {
1019            if (table.config.debug) {
1020                var time = new Date();
1021            }
1022            var $tr, row = -1,
1023                odd;
1024            // loop through the visible rows
1025            $("tr:visible", table.tBodies[0]).each(function (i) {
1026                $tr = $(this);
1027                // style children rows the same way the parent
1028                // row was styled
1029                if (!$tr.hasClass(table.config.cssChildRow)) row++;
1030                odd = (row % 2 == 0);
1031                $tr.removeClass(
1032                table.config.widgetZebra.css[odd ? 0 : 1]).addClass(
1033                table.config.widgetZebra.css[odd ? 1 : 0])
1034            });
1035            if (table.config.debug) {
1036                $.tablesorter.benchmark("Applying Zebra widget", time);
1037            }
1038        }
1039    });
1040})(jQuery);
Note: See TracBrowser for help on using the repository browser.