Changeset 26933


Ignore:
Timestamp:
01/23/14 21:24:23 (5 years ago)
Author:
Eric
Message:

Piwigo 2.6 compliance - Step 3:
Update tablesorter jquery plugin for compliance with jquery v1.10

HTML5 validation

Location:
extensions/UserAdvManager/trunk/admin/template
Files:
1 added
1 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • extensions/UserAdvManager/trunk/admin/template/ghosttracker.tpl

    r21747 r26933  
    22{combine_script id='jquery.cluetip' require='jquery' path='themes/default/js/plugins/jquery.cluetip.js'} 
    33{combine_script id='jquery.tablesorter' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.min.js'} 
    4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.js'} 
     4{combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.min.js'} 
    55 
    66{combine_css path= $UAM_PATH|@cat:'admin/template/uam.css'} 
     
    1919    {ldelim} 
    2020      $("#sorting") 
    21       .tablesorter({ldelim}sortList:[[4,1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim}{rdelim}{rdelim}) 
     21      .tablesorter({ldelim}sortList:[[4,1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim},2: {ldelim} sorter: false {rdelim}{rdelim}{rdelim}) 
    2222      .tablesorterPager({ldelim}container: $("#pager"), positionFixed: false, size: 20, totalPages: 0{rdelim}); 
    2323    {rdelim}); 
  • extensions/UserAdvManager/trunk/admin/template/js/jquery.metadata.js

    r6378 r26933  
    22 * Metadata - jQuery plugin for parsing metadata from elements 
    33 * 
    4  * Copyright (c) 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan 
     4 * Copyright (c) 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan 
    55 * 
    66 * Dual licensed under the MIT and GPL licenses: 
    77 *   http://www.opensource.org/licenses/mit-license.php 
    88 *   http://www.gnu.org/licenses/gpl.html 
    9  * 
    10  * Revision: $Id$ 
    119 * 
    1210 */ 
     
    1917 * 
    2018 *   attr:  Inside an attribute. The name parameter indicates *which* attribute. 
    21  *           
     19 * 
    2220 *   class: Inside the class attribute, wrapped in curly braces: { } 
    23  *    
     21 * 
    2422 *   elem:  Inside a child element (e.g. a script tag). The 
    2523 *          name parameter indicates *which* element. 
    26  *           
     24 * 
    2725 * The metadata for an element is loaded the first time the element is accessed via jQuery. 
    2826 * 
    2927 * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements 
    3028 * matched by expr, then redefine the metadata type and run another $(expr) for other elements. 
    31  *  
     29 * 
    3230 * @name $.metadata.setType 
    3331 * 
     
    3634 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 
    3735 * @desc Reads metadata from the class attribute 
    38  *  
     36 * 
    3937 * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p> 
    4038 * @before $.metadata.setType("attr", "data") 
    4139 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 
    4240 * @desc Reads metadata from a "data" attribute 
    43  *  
     41 * 
    4442 * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p> 
    4543 * @before $.metadata.setType("elem", "script") 
    4644 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 
    4745 * @desc Reads metadata from a nested script element 
    48  *  
     46 * 
    4947 * @param String type The encoding type 
    5048 * @param String name The name of the attribute to be used to get metadata (optional) 
     
    6260                        type: 'class', 
    6361                        name: 'metadata', 
    64                         cre: /({.*})/, 
     62                        cre: /(\{.*\})/, 
    6563                        single: 'metadata' 
    6664                }, 
     
    7068                }, 
    7169                get: function( elem, opts ){ 
    72                         var settings = $.extend({},this.defaults,opts); 
     70                        var data, m, e, attr, 
     71                                settings = $.extend({},this.defaults,opts); 
    7372                        // check for empty string in single property 
    74                         if ( !settings.single.length ) settings.single = 'metadata'; 
    75                          
    76                         var data = $.data(elem, settings.single); 
     73                        if ( !settings.single.length ) { settings.single = 'metadata'; } 
     74 
     75                        data = $.data(elem, settings.single); 
    7776                        // returned cached data if it already exists 
    78                         if ( data ) return data; 
    79                          
     77                        if ( data ) { return data; } 
     78 
    8079                        data = "{}"; 
    81                          
    82                         if ( settings.type == "class" ) { 
    83                                 var m = settings.cre.exec( elem.className ); 
    84                                 if ( m ) 
    85                                         data = m[1]; 
    86                         } else if ( settings.type == "elem" ) { 
    87                                 if( !elem.getElementsByTagName ) 
    88                                         return undefined; 
    89                                 var e = elem.getElementsByTagName(settings.name); 
    90                                 if ( e.length ) 
    91                                         data = $.trim(e[0].innerHTML); 
    92                         } else if ( elem.getAttribute != undefined ) { 
    93                                 var attr = elem.getAttribute( settings.name ); 
    94                                 if ( attr ) 
    95                                         data = attr; 
     80 
     81                        if ( settings.type === "class" ) { 
     82                                m = settings.cre.exec( elem.className ); 
     83                                if ( m ) { data = m[1]; } 
     84                        } else if ( settings.type === "elem" ) { 
     85                                if( !elem.getElementsByTagName ) { return undefined; } 
     86                                e = elem.getElementsByTagName(settings.name); 
     87                                if ( e.length ) { data = $.trim(e[0].innerHTML); } 
     88                        } else if ( elem.getAttribute !== undefined ) { 
     89                                attr = elem.getAttribute( settings.name ); 
     90                                if ( attr ) { data = attr; } 
    9691                        } 
    97                          
    98                         if ( data.indexOf( '{' ) <0 ) 
    99                         data = "{" + data + "}"; 
    100                          
     92 
     93                        if ( data.indexOf( '{' ) <0 ) { data = "{" + data + "}"; } 
     94 
    10195                        data = eval("(" + data + ")"); 
    102                          
     96 
    10397                        $.data( elem, settings.single, data ); 
    10498                        return data; 
  • extensions/UserAdvManager/trunk/admin/template/js/jquery.tablesorter.js

    r8875 r26933  
    1 /* 
    2  *  
    3  * TableSorter 2.0 - Client-side table sorting with ease! 
    4  * Version 2.0.5b 
    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                 var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0, 
    255                     totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0, 
    256                     parsers = table.config.parsers, 
    257                     cache = { 
    258                         row: [], 
    259                         normalized: [] 
    260                     }; 
    261  
    262                 for (var i = 0; i < totalRows; ++i) { 
    263  
    264                     /** Add the table data to main data array */ 
    265                     var c = $(table.tBodies[0].rows[i]), 
    266                         cols = []; 
    267  
    268                     // if this is a child row, add it to the last row's children and 
    269                     // continue to the next row 
    270                     if (c.hasClass(table.config.cssChildRow)) { 
    271                         cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c); 
    272                         // go to the next for loop 
    273                         continue; 
    274                     } 
    275  
    276                     cache.row.push(c); 
    277  
    278                     for (var j = 0; j < totalCells; ++j) { 
    279                         cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j])); 
    280                     } 
    281  
    282                     cols.push(cache.normalized.length); // add position for rowCache 
    283                     cache.normalized.push(cols); 
    284                     cols = null; 
    285                 }; 
    286  
    287                 if (table.config.debug) { 
    288                     benchmark("Building cache for " + totalRows + " rows:", cacheTime); 
    289                 } 
    290  
    291                 return cache; 
    292             }; 
    293  
    294             function getElementText(config, node) { 
    295  
    296                 var text = ""; 
    297  
    298                 if (!node) return ""; 
    299  
    300                 if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false; 
    301  
    302                 if (config.textExtraction == "simple") { 
    303                     if (config.supportsTextContent) { 
    304                         text = node.textContent; 
    305                     } else { 
    306                         if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) { 
    307                             text = node.childNodes[0].innerHTML; 
    308                         } else { 
    309                             text = node.innerHTML; 
    310                         } 
    311                     } 
    312                 } else { 
    313                     if (typeof(config.textExtraction) == "function") { 
    314                         text = config.textExtraction(node); 
    315                     } else { 
    316                         text = $(node).text(); 
    317                     } 
    318                 } 
    319                 return text; 
    320             } 
    321  
    322             function appendToTable(table, cache) { 
    323  
    324                 if (table.config.debug) { 
    325                     var appendTime = new Date() 
    326                 } 
    327  
    328                 var c = cache, 
    329                     r = c.row, 
    330                     n = c.normalized, 
    331                     totalRows = n.length, 
    332                     checkCell = (n[0].length - 1), 
    333                     tableBody = $(table.tBodies[0]), 
    334                     rows = []; 
    335  
    336  
    337                 for (var i = 0; i < totalRows; i++) { 
    338                     var pos = n[i][checkCell]; 
    339  
    340                     rows.push(r[pos]); 
    341  
    342                     if (!table.config.appender) { 
    343  
    344                         //var o = ; 
    345                         var l = r[pos].length; 
    346                         for (var j = 0; j < l; j++) { 
    347                             tableBody[0].appendChild(r[pos][j]); 
    348                         } 
    349  
    350                         //  
    351                     } 
    352                 } 
    353  
    354  
    355  
    356                 if (table.config.appender) { 
    357  
    358                     table.config.appender(table, rows); 
    359                 } 
    360  
    361                 rows = null; 
    362  
    363                 if (table.config.debug) { 
    364                     benchmark("Rebuilt table:", appendTime); 
    365                 } 
    366  
    367                 // apply table widgets 
    368                 applyWidget(table); 
    369  
    370                 // trigger sortend 
    371                 setTimeout(function () { 
    372                     $(table).trigger("sortEnd"); 
    373                 }, 0); 
    374  
    375             }; 
    376  
    377             function buildHeaders(table) { 
    378  
    379                 if (table.config.debug) { 
    380                     var time = new Date(); 
    381                 } 
    382  
    383                 var meta = ($.metadata) ? true : false; 
    384                  
    385                 var header_index = computeTableHeaderCellIndexes(table); 
    386  
    387                 $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) { 
    388  
    389                     this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; 
    390                     // this.column = index; 
    391                     this.order = formatSortingOrder(table.config.sortInitialOrder); 
    392                      
    393                                          
    394                                         this.count = this.order; 
    395  
    396                     if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true; 
    397                                         if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index); 
    398  
    399                     if (!this.sortDisabled) { 
    400                         var $th = $(this).addClass(table.config.cssHeader); 
    401                         if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th); 
    402                     } 
    403  
    404                     // add cell to headerList 
    405                     table.config.headerList[index] = this; 
    406                 }); 
    407  
    408                 if (table.config.debug) { 
    409                     benchmark("Built headers:", time); 
    410                     log($tableHeaders); 
    411                 } 
    412  
    413                 return $tableHeaders; 
    414  
    415             }; 
    416  
    417             // from: 
    418             // http://www.javascripttoolbox.com/lib/table/examples.php 
    419             // http://www.javascripttoolbox.com/temp/table_cellindex.html 
    420  
    421  
    422             function computeTableHeaderCellIndexes(t) { 
    423                 var matrix = []; 
    424                 var lookup = {}; 
    425                 var thead = t.getElementsByTagName('THEAD')[0]; 
    426                 var trs = thead.getElementsByTagName('TR'); 
    427  
    428                 for (var i = 0; i < trs.length; i++) { 
    429                     var cells = trs[i].cells; 
    430                     for (var j = 0; j < cells.length; j++) { 
    431                         var c = cells[j]; 
    432  
    433                         var rowIndex = c.parentNode.rowIndex; 
    434                         var cellId = rowIndex + "-" + c.cellIndex; 
    435                         var rowSpan = c.rowSpan || 1; 
    436                         var colSpan = c.colSpan || 1 
    437                         var firstAvailCol; 
    438                         if (typeof(matrix[rowIndex]) == "undefined") { 
    439                             matrix[rowIndex] = []; 
    440                         } 
    441                         // Find first available column in the first row 
    442                         for (var k = 0; k < matrix[rowIndex].length + 1; k++) { 
    443                             if (typeof(matrix[rowIndex][k]) == "undefined") { 
    444                                 firstAvailCol = k; 
    445                                 break; 
    446                             } 
    447                         } 
    448                         lookup[cellId] = firstAvailCol; 
    449                         for (var k = rowIndex; k < rowIndex + rowSpan; k++) { 
    450                             if (typeof(matrix[k]) == "undefined") { 
    451                                 matrix[k] = []; 
    452                             } 
    453                             var matrixrow = matrix[k]; 
    454                             for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) { 
    455                                 matrixrow[l] = "x"; 
    456                             } 
    457                         } 
    458                     } 
    459                 } 
    460                 return lookup; 
    461             } 
    462  
    463             function checkCellColSpan(table, rows, row) { 
    464                 var arr = [], 
    465                     r = table.tHead.rows, 
    466                     c = r[row].cells; 
    467  
    468                 for (var i = 0; i < c.length; i++) { 
    469                     var cell = c[i]; 
    470  
    471                     if (cell.colSpan > 1) { 
    472                         arr = arr.concat(checkCellColSpan(table, headerArr, row++)); 
    473                     } else { 
    474                         if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) { 
    475                             arr.push(cell); 
    476                         } 
    477                         // headerArr[row] = (i+row); 
    478                     } 
    479                 } 
    480                 return arr; 
    481             }; 
    482  
    483             function checkHeaderMetadata(cell) { 
    484                 if (($.metadata) && ($(cell).metadata().sorter === false)) { 
    485                     return true; 
    486                 }; 
    487                 return false; 
    488             } 
    489  
    490             function checkHeaderOptions(table, i) { 
    491                 if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { 
    492                     return true; 
    493                 }; 
    494                 return false; 
    495             } 
    496                          
    497                          function checkHeaderOptionsSortingLocked(table, i) { 
    498                 if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder; 
    499                 return false; 
    500             } 
    501                          
    502             function applyWidget(table) { 
    503                 var c = table.config.widgets; 
    504                 var l = c.length; 
    505                 for (var i = 0; i < l; i++) { 
    506  
    507                     getWidgetById(c[i]).format(table); 
    508                 } 
    509  
    510             } 
    511  
    512             function getWidgetById(name) { 
    513                 var l = widgets.length; 
    514                 for (var i = 0; i < l; i++) { 
    515                     if (widgets[i].id.toLowerCase() == name.toLowerCase()) { 
    516                         return widgets[i]; 
    517                     } 
    518                 } 
    519             }; 
    520  
    521             function formatSortingOrder(v) { 
    522                 if (typeof(v) != "Number") { 
    523                     return (v.toLowerCase() == "desc") ? 1 : 0; 
    524                 } else { 
    525                     return (v == 1) ? 1 : 0; 
    526                 } 
    527             } 
    528  
    529             function isValueInArray(v, a) { 
    530                 var l = a.length; 
    531                 for (var i = 0; i < l; i++) { 
    532                     if (a[i][0] == v) { 
    533                         return true; 
    534                     } 
    535                 } 
    536                 return false; 
    537             } 
    538  
    539             function setHeadersCss(table, $headers, list, css) { 
    540                 // remove all header information 
    541                 $headers.removeClass(css[0]).removeClass(css[1]); 
    542  
    543                 var h = []; 
    544                 $headers.each(function (offset) { 
    545                     if (!this.sortDisabled) { 
    546                         h[this.column] = $(this); 
    547                     } 
    548                 }); 
    549  
    550                 var l = list.length; 
    551                 for (var i = 0; i < l; i++) { 
    552                     h[list[i][0]].addClass(css[list[i][1]]); 
    553                 } 
    554             } 
    555  
    556             function fixColumnWidth(table, $headers) { 
    557                 var c = table.config; 
    558                 if (c.widthFixed) { 
    559                     var colgroup = $('<colgroup>'); 
    560                     $("tr:first td", table.tBodies[0]).each(function () { 
    561                         colgroup.append($('<col>').css('width', $(this).width())); 
    562                     }); 
    563                     $(table).prepend(colgroup); 
    564                 }; 
    565             } 
    566  
    567             function updateHeaderSortCount(table, sortList) { 
    568                 var c = table.config, 
    569                     l = sortList.length; 
    570                 for (var i = 0; i < l; i++) { 
    571                     var s = sortList[i], 
    572                         o = c.headerList[s[0]]; 
    573                     o.count = s[1]; 
    574                     o.count++; 
    575                 } 
    576             } 
    577  
    578             /* sorting methods */ 
    579  
    580             function multisort(table, sortList, cache) { 
    581  
    582                 if (table.config.debug) { 
    583                     var sortTime = new Date(); 
    584                 } 
    585  
    586                 var dynamicExp = "var sortWrapper = function(a,b) {", 
    587                     l = sortList.length; 
    588  
    589                 // TODO: inline functions. 
    590                 for (var i = 0; i < l; i++) { 
    591  
    592                     var c = sortList[i][0]; 
    593                     var order = sortList[i][1]; 
    594                     // var s = (getCachedSortType(table.config.parsers,c) == "text") ? 
    595                     // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? 
    596                     // "sortNumeric" : "sortNumericDesc"); 
    597                     // var s = (table.config.parsers[c].type == "text") ? ((order == 0) 
    598                     // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ? 
    599                     // makeSortNumeric(c) : makeSortNumericDesc(c)); 
    600                     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)); 
    601                     var e = "e" + i; 
    602  
    603                     dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c 
    604                     // + "]); "; 
    605                     dynamicExp += "if(" + e + ") { return " + e + "; } "; 
    606                     dynamicExp += "else { "; 
    607  
    608                 } 
    609  
    610                 // if value is the same keep orignal order 
    611                 var orgOrderCol = cache.normalized[0].length - 1; 
    612                 dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];"; 
    613  
    614                 for (var i = 0; i < l; i++) { 
    615                     dynamicExp += "}; "; 
    616                 } 
    617  
    618                 dynamicExp += "return 0; "; 
    619                 dynamicExp += "}; "; 
    620  
    621                 if (table.config.debug) { 
    622                     benchmark("Evaling expression:" + dynamicExp, new Date()); 
    623                 } 
    624  
    625                 eval(dynamicExp); 
    626  
    627                 cache.normalized.sort(sortWrapper); 
    628  
    629                 if (table.config.debug) { 
    630                     benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime); 
    631                 } 
    632  
    633                 return cache; 
    634             }; 
    635  
    636             function makeSortFunction(type, direction, index) { 
    637                 var a = "a[" + index + "]", 
    638                     b = "b[" + index + "]"; 
    639                 if (type == 'text' && direction == 'asc') { 
    640                     return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));"; 
    641                 } else if (type == 'text' && direction == 'desc') { 
    642                     return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));"; 
    643                 } else if (type == 'numeric' && direction == 'asc') { 
    644                     return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));"; 
    645                 } else if (type == 'numeric' && direction == 'desc') { 
    646                     return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));"; 
    647                 } 
    648             }; 
    649  
    650             function makeSortText(i) { 
    651                 return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));"; 
    652             }; 
    653  
    654             function makeSortTextDesc(i) { 
    655                 return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));"; 
    656             }; 
    657  
    658             function makeSortNumeric(i) { 
    659                 return "a[" + i + "]-b[" + i + "];"; 
    660             }; 
    661  
    662             function makeSortNumericDesc(i) { 
    663                 return "b[" + i + "]-a[" + i + "];"; 
    664             }; 
    665  
    666             function sortText(a, b) { 
    667                 if (table.config.sortLocaleCompare) return a.localeCompare(b); 
    668                 return ((a < b) ? -1 : ((a > b) ? 1 : 0)); 
    669             }; 
    670  
    671             function sortTextDesc(a, b) { 
    672                 if (table.config.sortLocaleCompare) return b.localeCompare(a); 
    673                 return ((b < a) ? -1 : ((b > a) ? 1 : 0)); 
    674             }; 
    675  
    676             function sortNumeric(a, b) { 
    677                 return a - b; 
    678             }; 
    679  
    680             function sortNumericDesc(a, b) { 
    681                 return b - a; 
    682             }; 
    683  
    684             function getCachedSortType(parsers, i) { 
    685                 return parsers[i].type; 
    686             }; /* public methods */ 
    687             this.construct = function (settings) { 
    688                 return this.each(function () { 
    689                     // if no thead or tbody quit. 
    690                     if (!this.tHead || !this.tBodies) return; 
    691                     // declare 
    692                     var $this, $document, $headers, cache, config, shiftDown = 0, 
    693                         sortOrder; 
    694                     // new blank config object 
    695                     this.config = {}; 
    696                     // merge and extend. 
    697                     config = $.extend(this.config, $.tablesorter.defaults, settings); 
    698                     // store common expression for speed 
    699                     $this = $(this); 
    700                     // save the settings where they read 
    701                     $.data(this, "tablesorter", config); 
    702                     // build headers 
    703                     $headers = buildHeaders(this); 
    704                     // try to auto detect column type, and store in tables config 
    705                     this.config.parsers = buildParserCache(this, $headers); 
    706                     // build the cache for the tbody cells 
    707                     cache = buildCache(this); 
    708                     // get the css class names, could be done else where. 
    709                     var sortCSS = [config.cssDesc, config.cssAsc]; 
    710                     // fixate columns if the users supplies the fixedWidth option 
    711                     fixColumnWidth(this); 
    712                     // apply event handling to headers 
    713                     // this is to big, perhaps break it out? 
    714                     $headers.click( 
    715  
    716                     function (e) { 
    717                         var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0; 
    718                         if (!this.sortDisabled && totalRows > 0) { 
    719                             // Only call sortStart if sorting is 
    720                             // enabled. 
    721                             $this.trigger("sortStart"); 
    722                             // store exp, for speed 
    723                             var $cell = $(this); 
    724                             // get current column index 
    725                             var i = this.column; 
    726                             // get current column sort order 
    727                             this.order = this.count++ % 2; 
    728                                                         // always sort on the locked order. 
    729                                                         if(this.lockedOrder) this.order = this.lockedOrder; 
    730                                                          
    731                                                         // user only whants to sort on one 
    732                             // column 
    733                             if (!e[config.sortMultiSortKey]) { 
    734                                 // flush the sort list 
    735                                 config.sortList = []; 
    736                                 if (config.sortForce != null) { 
    737                                     var a = config.sortForce; 
    738                                     for (var j = 0; j < a.length; j++) { 
    739                                         if (a[j][0] != i) { 
    740                                             config.sortList.push(a[j]); 
    741                                         } 
    742                                     } 
    743                                 } 
    744                                 // add column to sort list 
    745                                 config.sortList.push([i, this.order]); 
    746                                 // multi column sorting 
    747                             } else { 
    748                                 // the user has clicked on an all 
    749                                 // ready sortet column. 
    750                                 if (isValueInArray(i, config.sortList)) { 
    751                                     // revers the sorting direction 
    752                                     // for all tables. 
    753                                     for (var j = 0; j < config.sortList.length; j++) { 
    754                                         var s = config.sortList[j], 
    755                                             o = config.headerList[s[0]]; 
    756                                         if (s[0] == i) { 
    757                                             o.count = s[1]; 
    758                                             o.count++; 
    759                                             s[1] = o.count % 2; 
    760                                         } 
    761                                     } 
    762                                 } else { 
    763                                     // add column to sort list array 
    764                                     config.sortList.push([i, this.order]); 
    765                                 } 
    766                             }; 
    767                             setTimeout(function () { 
    768                                 // set css for headers 
    769                                 setHeadersCss($this[0], $headers, config.sortList, sortCSS); 
    770                                 appendToTable( 
    771                                         $this[0], multisort( 
    772                                         $this[0], config.sortList, cache) 
    773                                                                 ); 
    774                             }, 1); 
    775                             // stop normal event by returning false 
    776                             return false; 
    777                         } 
    778                         // cancel selection 
    779                     }).mousedown(function () { 
    780                         if (config.cancelSelection) { 
    781                             this.onselectstart = function () { 
    782                                 return false 
    783                             }; 
    784                             return false; 
    785                         } 
    786                     }); 
    787                     // apply easy methods that trigger binded events 
    788                     $this.bind("update", function () { 
    789                         var me = this; 
    790                         setTimeout(function () { 
    791                             // rebuild parsers. 
    792                             me.config.parsers = buildParserCache( 
    793                             me, $headers); 
    794                             // rebuild the cache map 
    795                             cache = buildCache(me); 
    796                         }, 1); 
    797                     }).bind("updateCell", function (e, cell) { 
    798                         var config = this.config; 
    799                         // get position from the dom. 
    800                         var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex]; 
    801                         // update cache 
    802                         cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format( 
    803                         getElementText(config, cell), cell); 
    804                     }).bind("sorton", function (e, list) { 
    805                         $(this).trigger("sortStart"); 
    806                         config.sortList = list; 
    807                         // update and store the sortlist 
    808                         var sortList = config.sortList; 
    809                         // update header count index 
    810                         updateHeaderSortCount(this, sortList); 
    811                         // set css for headers 
    812                         setHeadersCss(this, $headers, sortList, sortCSS); 
    813                         // sort the table and append it to the dom 
    814                         appendToTable(this, multisort(this, sortList, cache)); 
    815                     }).bind("appendCache", function () { 
    816                         appendToTable(this, cache); 
    817                     }).bind("applyWidgetId", function (e, id) { 
    818                         getWidgetById(id).format(this); 
    819                     }).bind("applyWidgets", function () { 
    820                         // apply widgets 
    821                         applyWidget(this); 
    822                     }); 
    823                     if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) { 
    824                         config.sortList = $(this).metadata().sortlist; 
    825                     } 
    826                     // if user has supplied a sort list to constructor. 
    827                     if (config.sortList.length > 0) { 
    828                         $this.trigger("sorton", [config.sortList]); 
    829                     } 
    830                     // apply widgets 
    831                     applyWidget(this); 
    832                 }); 
    833             }; 
    834             this.addParser = function (parser) { 
    835                 var l = parsers.length, 
    836                     a = true; 
    837                 for (var i = 0; i < l; i++) { 
    838                     if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) { 
    839                         a = false; 
    840                     } 
    841                 } 
    842                 if (a) { 
    843                     parsers.push(parser); 
    844                 }; 
    845             }; 
    846             this.addWidget = function (widget) { 
    847                 widgets.push(widget); 
    848             }; 
    849             this.formatFloat = function (s) { 
    850                 var i = parseFloat(s); 
    851                 return (isNaN(i)) ? 0 : i; 
    852             }; 
    853             this.formatInt = function (s) { 
    854                 var i = parseInt(s); 
    855                 return (isNaN(i)) ? 0 : i; 
    856             }; 
    857             this.isDigit = function (s, config) { 
    858                 // replace all an wanted chars and match. 
    859                 return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, ''))); 
    860             }; 
    861             this.clearTableBody = function (table) { 
    862                 if ($.browser.msie) { 
    863                     function empty() { 
    864                         while (this.firstChild) 
    865                         this.removeChild(this.firstChild); 
    866                     } 
    867                     empty.apply(table.tBodies[0]); 
    868                 } else { 
    869                     table.tBodies[0].innerHTML = ""; 
    870                 } 
    871             }; 
    872         } 
    873     }); 
    874  
    875     // extend plugin scope 
    876     $.fn.extend({ 
    877         tablesorter: $.tablesorter.construct 
    878     }); 
    879  
    880     // make shortcut 
    881     var ts = $.tablesorter; 
    882  
    883     // add default parsers 
    884     ts.addParser({ 
    885         id: "text", 
    886         is: function (s) { 
    887             return true; 
    888         }, format: function (s) { 
    889             return $.trim(s.toLocaleLowerCase()); 
    890         }, type: "text" 
    891     }); 
    892  
    893     ts.addParser({ 
    894         id: "digit", 
    895         is: function (s, table) { 
    896             var c = table.config; 
    897             return $.tablesorter.isDigit(s, c); 
    898         }, format: function (s) { 
    899             return $.tablesorter.formatFloat(s); 
    900         }, type: "numeric" 
    901     }); 
    902  
    903     ts.addParser({ 
    904         id: "currency", 
    905         is: function (s) { 
    906             return /^[£$€?.]/.test(s); 
    907         }, format: function (s) { 
    908             return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), "")); 
    909         }, type: "numeric" 
    910     }); 
    911  
    912     ts.addParser({ 
    913         id: "ipAddress", 
    914         is: function (s) { 
    915             return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s); 
    916         }, format: function (s) { 
    917             var a = s.split("."), 
    918                 r = "", 
    919                 l = a.length; 
    920             for (var i = 0; i < l; i++) { 
    921                 var item = a[i]; 
    922                 if (item.length == 2) { 
    923                     r += "0" + item; 
    924                 } else { 
    925                     r += item; 
    926                 } 
    927             } 
    928             return $.tablesorter.formatFloat(r); 
    929         }, type: "numeric" 
    930     }); 
    931  
    932     ts.addParser({ 
    933         id: "url", 
    934         is: function (s) { 
    935             return /^(https?|ftp|file):\/\/$/.test(s); 
    936         }, format: function (s) { 
    937             return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), '')); 
    938         }, type: "text" 
    939     }); 
    940  
    941     ts.addParser({ 
    942         id: "isoDate", 
    943         is: function (s) { 
    944             return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s); 
    945         }, format: function (s) { 
    946             return $.tablesorter.formatFloat((s != "") ? new Date(s.replace( 
    947             new RegExp(/-/g), "/")).getTime() : "0"); 
    948         }, type: "numeric" 
    949     }); 
    950  
    951     ts.addParser({ 
    952         id: "percent", 
    953         is: function (s) { 
    954             return /\%$/.test($.trim(s)); 
    955         }, format: function (s) { 
    956             return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), "")); 
    957         }, type: "numeric" 
    958     }); 
    959  
    960     ts.addParser({ 
    961         id: "usLongDate", 
    962         is: function (s) { 
    963             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)))$/)); 
    964         }, format: function (s) { 
    965             return $.tablesorter.formatFloat(new Date(s).getTime()); 
    966         }, type: "numeric" 
    967     }); 
    968  
    969     ts.addParser({ 
    970         id: "shortDate", 
    971         is: function (s) { 
    972             return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s); 
    973         }, format: function (s, table) { 
    974             var c = table.config; 
    975             s = s.replace(/\-/g, "/"); 
    976             if (c.dateFormat == "us") { 
    977                 // reformat the string in ISO format 
    978                 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2"); 
    979             } else if (c.dateFormat == "uk") { 
    980                 // reformat the string in ISO format 
    981                 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1"); 
    982             } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") { 
    983                 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3"); 
    984             } 
    985             return $.tablesorter.formatFloat(new Date(s).getTime()); 
    986         }, type: "numeric" 
    987     }); 
    988     ts.addParser({ 
    989         id: "time", 
    990         is: function (s) { 
    991             return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s); 
    992         }, format: function (s) { 
    993             return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime()); 
    994         }, type: "numeric" 
    995     }); 
    996     ts.addParser({ 
    997         id: "metadata", 
    998         is: function (s) { 
    999             return false; 
    1000         }, format: function (s, table, cell) { 
    1001             var c = table.config, 
    1002                 p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; 
    1003             return $(cell).metadata()[p]; 
    1004         }, type: "numeric" 
    1005     }); 
    1006     // add default widgets 
    1007     ts.addWidget({ 
    1008         id: "zebra", 
    1009         format: function (table) { 
    1010             if (table.config.debug) { 
    1011                 var time = new Date(); 
    1012             } 
    1013             var $tr, row = -1, 
    1014                 odd; 
    1015             // loop through the visible rows 
    1016             $("tr:visible", table.tBodies[0]).each(function (i) { 
    1017                 $tr = $(this); 
    1018                 // style children rows the same way the parent 
    1019                 // row was styled 
    1020                 if (!$tr.hasClass(table.config.cssChildRow)) row++; 
    1021                 odd = (row % 2 == 0); 
    1022                 $tr.removeClass( 
    1023                 table.config.widgetZebra.css[odd ? 0 : 1]).addClass( 
    1024                 table.config.widgetZebra.css[odd ? 1 : 0]) 
    1025             }); 
    1026             if (table.config.debug) { 
    1027                 $.tablesorter.benchmark("Applying Zebra widget", time); 
    1028             } 
    1029         } 
    1030     }); 
     1/**! 
     2* TableSorter 2.14.5 - Client-side table sorting with ease! 
     3* @requires jQuery v1.2.6+ 
     4* 
     5* Copyright (c) 2007 Christian Bach 
     6* Examples and docs at: http://tablesorter.com 
     7* Dual licensed under the MIT and GPL licenses: 
     8* http://www.opensource.org/licenses/mit-license.php 
     9* http://www.gnu.org/licenses/gpl.html 
     10* 
     11* @type jQuery 
     12* @name tablesorter 
     13* @cat Plugins/Tablesorter 
     14* @author Christian Bach/christian.bach@polyester.se 
     15* @contributor Rob Garrison/https://github.com/Mottie/tablesorter 
     16*/ 
     17/*jshint browser:true, jquery:true, unused:false, expr: true */ 
     18/*global console:false, alert:false */ 
     19!(function($) { 
     20        "use strict"; 
     21        $.extend({ 
     22                /*jshint supernew:true */ 
     23                tablesorter: new function() { 
     24 
     25                        var ts = this; 
     26 
     27                        ts.version = "2.14.5"; 
     28 
     29                        ts.parsers = []; 
     30                        ts.widgets = []; 
     31                        ts.defaults = { 
     32 
     33                                // *** appearance 
     34                                theme            : 'default',  // adds tablesorter-{theme} to the table for styling 
     35                                widthFixed       : false,      // adds colgroup to fix widths of columns 
     36                                showProcessing   : false,      // show an indeterminate timer icon in the header when the table is sorted or filtered. 
     37 
     38                                headerTemplate   : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> (class from cssIcon) 
     39                                onRenderTemplate : null,       // function(index, template){ return template; }, (template is a string) 
     40                                onRenderHeader   : null,       // function(index){}, (nothing to return) 
     41 
     42                                // *** functionality 
     43                                cancelSelection  : true,       // prevent text selection in the header 
     44                                tabIndex         : true,       // add tabindex to header for keyboard accessibility 
     45                                dateFormat       : 'mmddyyyy', // other options: "ddmmyyy" or "yyyymmdd" 
     46                                sortMultiSortKey : 'shiftKey', // key used to select additional columns 
     47                                sortResetKey     : 'ctrlKey',  // key used to remove sorting on a column 
     48                                usNumberFormat   : true,       // false for German "1.234.567,89" or French "1 234 567,89" 
     49                                delayInit        : false,      // if false, the parsed table contents will not update until the first sort 
     50                                serverSideSorting: false,      // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used. 
     51 
     52                                // *** sort options 
     53                                headers          : {},         // set sorter, string, empty, locked order, sortInitialOrder, filter, etc. 
     54                                ignoreCase       : true,       // ignore case while sorting 
     55                                sortForce        : null,       // column(s) first sorted; always applied 
     56                                sortList         : [],         // Initial sort order; applied initially; updated when manually sorted 
     57                                sortAppend       : null,       // column(s) sorted last; always applied 
     58                                sortStable       : false,      // when sorting two rows with exactly the same content, the original sort order is maintained 
     59 
     60                                sortInitialOrder : 'asc',      // sort direction on first click 
     61                                sortLocaleCompare: false,      // replace equivalent character (accented characters) 
     62                                sortReset        : false,      // third click on the header will reset column to default - unsorted 
     63                                sortRestart      : false,      // restart sort to "sortInitialOrder" when clicking on previously unsorted columns 
     64 
     65                                emptyTo          : 'bottom',   // sort empty cell to bottom, top, none, zero 
     66                                stringTo         : 'max',      // sort strings in numerical column as max, min, top, bottom, zero 
     67                                textExtraction   : 'simple',   // text extraction method/function - function(node, table, cellIndex){} 
     68                                textSorter       : null,       // choose overall or specific column sorter function(a, b, direction, table, columnIndex) [alt: ts.sortText] 
     69                                numberSorter     : null,       // choose overall numeric sorter function(a, b, direction, maxColumnValue) 
     70 
     71                                // *** widget options 
     72                                widgets: [],                   // method to add widgets, e.g. widgets: ['zebra'] 
     73                                widgetOptions    : { 
     74                                        zebra : [ 'even', 'odd' ]    // zebra widget alternating row class names 
     75                                }, 
     76                                initWidgets      : true,       // apply widgets on tablesorter initialization 
     77 
     78                                // *** callbacks 
     79                                initialized      : null,       // function(table){}, 
     80 
     81                                // *** extra css class names 
     82                                tableClass       : '', 
     83                                cssAsc           : '', 
     84                                cssDesc          : '', 
     85                                cssHeader        : '', 
     86                                cssHeaderRow     : '', 
     87                                cssProcessing    : '', // processing icon applied to header during sort/filter 
     88 
     89                                cssChildRow      : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent  
     90                                cssIcon          : 'tablesorter-icon',     //  if this class exists, a <i> will be added to the header automatically 
     91                                cssInfoBlock     : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!) 
     92 
     93                                // *** selectors 
     94                                selectorHeaders  : '> thead th, > thead td', 
     95                                selectorSort     : 'th, td',   // jQuery selector of content within selectorHeaders that is clickable to trigger a sort 
     96                                selectorRemove   : '.remove-me', 
     97 
     98                                // *** advanced 
     99                                debug            : false, 
     100 
     101                                // *** Internal variables 
     102                                headerList: [], 
     103                                empties: {}, 
     104                                strings: {}, 
     105                                parsers: [] 
     106 
     107                                // deprecated; but retained for backwards compatibility 
     108                                // widgetZebra: { css: ["even", "odd"] } 
     109 
     110                        }; 
     111 
     112                        // internal css classes - these will ALWAYS be added to 
     113                        // the table and MUST only contain one class name - fixes #381 
     114                        ts.css = { 
     115                                table      : 'tablesorter', 
     116                                childRow   : 'tablesorter-childRow', 
     117                                header     : 'tablesorter-header', 
     118                                headerRow  : 'tablesorter-headerRow', 
     119                                icon       : 'tablesorter-icon', 
     120                                info       : 'tablesorter-infoOnly', 
     121                                processing : 'tablesorter-processing', 
     122                                sortAsc    : 'tablesorter-headerAsc', 
     123                                sortDesc   : 'tablesorter-headerDesc' 
     124                        }; 
     125 
     126                        /* debuging utils */ 
     127                        function log() { 
     128                                var s = arguments.length > 1 ? Array.prototype.slice.call(arguments) : arguments[0]; 
     129                                if (typeof console !== "undefined" && typeof console.log !== "undefined") { 
     130                                        console.log(s); 
     131                                } else { 
     132                                        alert(s); 
     133                                } 
     134                        } 
     135 
     136                        function benchmark(s, d) { 
     137                                log(s + " (" + (new Date().getTime() - d.getTime()) + "ms)"); 
     138                        } 
     139 
     140                        ts.log = log; 
     141                        ts.benchmark = benchmark; 
     142 
     143                        // $.isEmptyObject from jQuery v1.4 
     144                        function isEmptyObject(obj) { 
     145                                /*jshint forin: false */ 
     146                                for (var name in obj) { 
     147                                        return false; 
     148                                } 
     149                                return true; 
     150                        } 
     151 
     152                        function getElementText(table, node, cellIndex) { 
     153                                if (!node) { return ""; } 
     154                                var c = table.config, 
     155                                        t = c.textExtraction, text = ""; 
     156                                if (t === "simple") { 
     157                                        if (c.supportsTextContent) { 
     158                                                text = node.textContent; // newer browsers support this 
     159                                        } else { 
     160                                                text = $(node).text(); 
     161                                        } 
     162                                } else { 
     163                                        if (typeof t === "function") { 
     164                                                text = t(node, table, cellIndex); 
     165                                        } else if (typeof t === "object" && t.hasOwnProperty(cellIndex)) { 
     166                                                text = t[cellIndex](node, table, cellIndex); 
     167                                        } else { 
     168                                                text = c.supportsTextContent ? node.textContent : $(node).text(); 
     169                                        } 
     170                                } 
     171                                return $.trim(text); 
     172                        } 
     173 
     174                        function detectParserForColumn(table, rows, rowIndex, cellIndex) { 
     175                                var cur, 
     176                                i = ts.parsers.length, 
     177                                node = false, 
     178                                nodeValue = '', 
     179                                keepLooking = true; 
     180                                while (nodeValue === '' && keepLooking) { 
     181                                        rowIndex++; 
     182                                        if (rows[rowIndex]) { 
     183                                                node = rows[rowIndex].cells[cellIndex]; 
     184                                                nodeValue = getElementText(table, node, cellIndex); 
     185                                                if (table.config.debug) { 
     186                                                        log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"'); 
     187                                                } 
     188                                        } else { 
     189                                                keepLooking = false; 
     190                                        } 
     191                                } 
     192                                while (--i >= 0) { 
     193                                        cur = ts.parsers[i]; 
     194                                        // ignore the default text parser because it will always be true 
     195                                        if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, table, node)) { 
     196                                                return cur; 
     197                                        } 
     198                                } 
     199                                // nothing found, return the generic parser (text) 
     200                                return ts.getParserById('text'); 
     201                        } 
     202 
     203                        function buildParserCache(table) { 
     204                                var c = table.config, 
     205                                        // update table bodies in case we start with an empty table 
     206                                        tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'), 
     207                                        rows, list, l, i, h, ch, p, time, parsersDebug = ""; 
     208                                if ( tb.length === 0) { 
     209                                        return c.debug ? log('*Empty table!* Not building a parser cache') : ''; 
     210                                } else if (c.debug) { 
     211                                        time = new Date(); 
     212                                        log('Detecting parsers for each column'); 
     213                                } 
     214                                rows = tb[0].rows; 
     215                                if (rows[0]) { 
     216                                        list = []; 
     217                                        l = rows[0].cells.length; 
     218                                        for (i = 0; i < l; i++) { 
     219                                                // tons of thanks to AnthonyM1229 for working out the following selector (issue #74) to make this work in IE8! 
     220                                                // More fixes to this selector to work properly in iOS and jQuery 1.8+ (issue #132 & #174) 
     221                                                h = c.$headers.filter(':not([colspan])'); 
     222                                                h = h.add( c.$headers.filter('[colspan="1"]') ) // ie8 fix 
     223                                                        .filter('[data-column="' + i + '"]:last'); 
     224                                                ch = c.headers[i]; 
     225                                                // get column parser 
     226                                                p = ts.getParserById( ts.getData(h, ch, 'sorter') ); 
     227                                                // empty cells behaviour - keeping emptyToBottom for backwards compatibility 
     228                                                c.empties[i] = ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ); 
     229                                                // text strings behaviour in numerical sorts 
     230                                                c.strings[i] = ts.getData(h, ch, 'string') || c.stringTo || 'max'; 
     231                                                if (!p) { 
     232                                                        p = detectParserForColumn(table, rows, -1, i); 
     233                                                } 
     234                                                if (c.debug) { 
     235                                                        parsersDebug += "column:" + i + "; parser:" + p.id + "; string:" + c.strings[i] + '; empty: ' + c.empties[i] + "\n"; 
     236                                                } 
     237                                                list.push(p); 
     238                                        } 
     239                                } 
     240                                if (c.debug) { 
     241                                        log(parsersDebug); 
     242                                        benchmark("Completed detecting parsers", time); 
     243                                } 
     244                                c.parsers = list; 
     245                        } 
     246 
     247                        /* utils */ 
     248                        function buildCache(table) { 
     249                                var b = table.tBodies, 
     250                                tc = table.config, 
     251                                totalRows, 
     252                                totalCells, 
     253                                parsers = tc.parsers, 
     254                                t, v, i, j, k, c, cols, cacheTime, colMax = []; 
     255                                tc.cache = {}; 
     256                                // if no parsers found, return - it's an empty table. 
     257                                if (!parsers) { 
     258                                        return tc.debug ? log('*Empty table!* Not building a cache') : ''; 
     259                                } 
     260                                if (tc.debug) { 
     261                                        cacheTime = new Date(); 
     262                                } 
     263                                // processing icon 
     264                                if (tc.showProcessing) { 
     265                                        ts.isProcessing(table, true); 
     266                                } 
     267                                for (k = 0; k < b.length; k++) { 
     268                                        tc.cache[k] = { row: [], normalized: [] }; 
     269                                        // ignore tbodies with class name from c.cssInfoBlock 
     270                                        if (!$(b[k]).hasClass(tc.cssInfoBlock)) { 
     271                                                totalRows = (b[k] && b[k].rows.length) || 0; 
     272                                                totalCells = (b[k].rows[0] && b[k].rows[0].cells.length) || 0; 
     273                                                for (i = 0; i < totalRows; ++i) { 
     274                                                        /** Add the table data to main data array */ 
     275                                                        c = $(b[k].rows[i]); 
     276                                                        cols = []; 
     277                                                        // if this is a child row, add it to the last row's children and continue to the next row 
     278                                                        if (c.hasClass(tc.cssChildRow)) { 
     279                                                                tc.cache[k].row[tc.cache[k].row.length - 1] = tc.cache[k].row[tc.cache[k].row.length - 1].add(c); 
     280                                                                // go to the next for loop 
     281                                                                continue; 
     282                                                        } 
     283                                                        tc.cache[k].row.push(c); 
     284                                                        for (j = 0; j < totalCells; ++j) { 
     285                                                                t = getElementText(table, c[0].cells[j], j); 
     286                                                                // allow parsing if the string is empty, previously parsing would change it to zero, 
     287                                                                // in case the parser needs to extract data from the table cell attributes 
     288                                                                v = parsers[j].format(t, table, c[0].cells[j], j); 
     289                                                                cols.push(v); 
     290                                                                if ((parsers[j].type || '').toLowerCase() === "numeric") { 
     291                                                                        colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0); // determine column max value (ignore sign) 
     292                                                                } 
     293                                                        } 
     294                                                        cols.push(tc.cache[k].normalized.length); // add position for rowCache 
     295                                                        tc.cache[k].normalized.push(cols); 
     296                                                } 
     297                                                tc.cache[k].colMax = colMax; 
     298                                        } 
     299                                } 
     300                                if (tc.showProcessing) { 
     301                                        ts.isProcessing(table); // remove processing icon 
     302                                } 
     303                                if (tc.debug) { 
     304                                        benchmark("Building cache for " + totalRows + " rows", cacheTime); 
     305                                } 
     306                        } 
     307 
     308                        // init flag (true) used by pager plugin to prevent widget application 
     309                        function appendToTable(table, init) { 
     310                                var c = table.config, 
     311                                        wo = c.widgetOptions, 
     312                                        b = table.tBodies, 
     313                                        rows = [], 
     314                                        c2 = c.cache, 
     315                                        r, n, totalRows, checkCell, $bk, $tb, 
     316                                        i, j, k, l, pos, appendTime; 
     317                                if (isEmptyObject(c2)) { return; } // empty table - fixes #206/#346 
     318                                if (c.debug) { 
     319                                        appendTime = new Date(); 
     320                                } 
     321                                for (k = 0; k < b.length; k++) { 
     322                                        $bk = $(b[k]); 
     323                                        if ($bk.length && !$bk.hasClass(c.cssInfoBlock)) { 
     324                                                // get tbody 
     325                                                $tb = ts.processTbody(table, $bk, true); 
     326                                                r = c2[k].row; 
     327                                                n = c2[k].normalized; 
     328                                                totalRows = n.length; 
     329                                                checkCell = totalRows ? (n[0].length - 1) : 0; 
     330                                                for (i = 0; i < totalRows; i++) { 
     331                                                        pos = n[i][checkCell]; 
     332                                                        rows.push(r[pos]); 
     333                                                        // removeRows used by the pager plugin; don't render if using ajax - fixes #411 
     334                                                        if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) { 
     335                                                                l = r[pos].length; 
     336                                                                for (j = 0; j < l; j++) { 
     337                                                                        $tb.append(r[pos][j]); 
     338                                                                } 
     339                                                        } 
     340                                                } 
     341                                                // restore tbody 
     342                                                ts.processTbody(table, $tb, false); 
     343                                        } 
     344                                } 
     345                                if (c.appender) { 
     346                                        c.appender(table, rows); 
     347                                } 
     348                                if (c.debug) { 
     349                                        benchmark("Rebuilt table", appendTime); 
     350                                } 
     351                                // apply table widgets; but not before ajax completes 
     352                                if (!init && !c.appender) { ts.applyWidget(table); } 
     353                                // trigger sortend 
     354                                $(table).trigger("sortEnd", table); 
     355                                $(table).trigger("updateComplete", table); 
     356                        } 
     357 
     358                        // computeTableHeaderCellIndexes from: 
     359                        // http://www.javascripttoolbox.com/lib/table/examples.php 
     360                        // http://www.javascripttoolbox.com/temp/table_cellindex.html 
     361                        function computeThIndexes(t) { 
     362                                var matrix = [], 
     363                                lookup = {}, 
     364                                cols = 0, // determine the number of columns 
     365                                trs = $(t).find('thead:eq(0), tfoot').children('tr'), // children tr in tfoot - see issue #196 
     366                                i, j, k, l, c, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, matrixrow; 
     367                                for (i = 0; i < trs.length; i++) { 
     368                                        cells = trs[i].cells; 
     369                                        for (j = 0; j < cells.length; j++) { 
     370                                                c = cells[j]; 
     371                                                rowIndex = c.parentNode.rowIndex; 
     372                                                cellId = rowIndex + "-" + c.cellIndex; 
     373                                                rowSpan = c.rowSpan || 1; 
     374                                                colSpan = c.colSpan || 1; 
     375                                                if (typeof(matrix[rowIndex]) === "undefined") { 
     376                                                        matrix[rowIndex] = []; 
     377                                                } 
     378                                                // Find first available column in the first row 
     379                                                for (k = 0; k < matrix[rowIndex].length + 1; k++) { 
     380                                                        if (typeof(matrix[rowIndex][k]) === "undefined") { 
     381                                                                firstAvailCol = k; 
     382                                                                break; 
     383                                                        } 
     384                                                } 
     385                                                lookup[cellId] = firstAvailCol; 
     386                                                cols = Math.max(firstAvailCol, cols); 
     387                                                // add data-column 
     388                                                $(c).attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex 
     389                                                for (k = rowIndex; k < rowIndex + rowSpan; k++) { 
     390                                                        if (typeof(matrix[k]) === "undefined") { 
     391                                                                matrix[k] = []; 
     392                                                        } 
     393                                                        matrixrow = matrix[k]; 
     394                                                        for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) { 
     395                                                                matrixrow[l] = "x"; 
     396                                                        } 
     397                                                } 
     398                                        } 
     399                                } 
     400                                // may not be accurate if # header columns !== # tbody columns 
     401                                t.config.columns = cols + 1; // add one because it's a zero-based index 
     402                                return lookup; 
     403                        } 
     404 
     405                        function formatSortingOrder(v) { 
     406                                // look for "d" in "desc" order; return true 
     407                                return (/^d/i.test(v) || v === 1); 
     408                        } 
     409 
     410                        function buildHeaders(table) { 
     411                                var header_index = computeThIndexes(table), ch, $t, 
     412                                        h, i, t, lock, time, c = table.config; 
     413                                c.headerList = []; 
     414                                c.headerContent = []; 
     415                                if (c.debug) { 
     416                                        time = new Date(); 
     417                                } 
     418                                // add icon if cssIcon option exists 
     419                                i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : ''; 
     420                                c.$headers = $(table).find(c.selectorHeaders).each(function(index) { 
     421                                        $t = $(this); 
     422                                        ch = c.headers[index]; 
     423                                        c.headerContent[index] = $(this).html(); // save original header content 
     424                                        // set up header template 
     425                                        t = c.headerTemplate.replace(/\{content\}/g, $(this).html()).replace(/\{icon\}/g, i); 
     426                                        if (c.onRenderTemplate) { 
     427                                                h = c.onRenderTemplate.apply($t, [index, t]); 
     428                                                if (h && typeof h === 'string') { t = h; } // only change t if something is returned 
     429                                        } 
     430                                        $(this).html('<div class="tablesorter-header-inner">' + t + '</div>'); // faster than wrapInner 
     431 
     432                                        if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index]); } 
     433 
     434                                        this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; 
     435                                        this.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2]; 
     436                                        this.count = -1; // set to -1 because clicking on the header automatically adds one 
     437                                        this.lockedOrder = false; 
     438                                        lock = ts.getData($t, ch, 'lockedOrder') || false; 
     439                                        if (typeof lock !== 'undefined' && lock !== false) { 
     440                                                this.order = this.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0]; 
     441                                        } 
     442                                        $t.addClass(ts.css.header + ' ' + c.cssHeader); 
     443                                        // add cell to headerList 
     444                                        c.headerList[index] = this; 
     445                                        // add to parent in case there are multiple rows 
     446                                        $t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow); 
     447                                        // allow keyboard cursor to focus on element 
     448                                        if (c.tabIndex) { $t.attr("tabindex", 0); } 
     449                                }); 
     450                                // enable/disable sorting 
     451                                updateHeader(table); 
     452                                if (c.debug) { 
     453                                        benchmark("Built headers:", time); 
     454                                        log(c.$headers); 
     455                                } 
     456                        } 
     457 
     458                        function commonUpdate(table, resort, callback) { 
     459                                var c = table.config; 
     460                                // remove rows/elements before update 
     461                                c.$table.find(c.selectorRemove).remove(); 
     462                                // rebuild parsers 
     463                                buildParserCache(table); 
     464                                // rebuild the cache map 
     465                                buildCache(table); 
     466                                checkResort(c.$table, resort, callback); 
     467                        } 
     468 
     469                        function updateHeader(table) { 
     470                                var s, c = table.config; 
     471                                c.$headers.each(function(index, th){ 
     472                                        s = ts.getData( th, c.headers[index], 'sorter' ) === 'false'; 
     473                                        th.sortDisabled = s; 
     474                                        $(th)[ s ? 'addClass' : 'removeClass' ]('sorter-false'); 
     475                                }); 
     476                        } 
     477 
     478                        function setHeadersCss(table) { 
     479                                var f, i, j, l, 
     480                                        c = table.config, 
     481                                        list = c.sortList, 
     482                                        css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc], 
     483                                        // find the footer 
     484                                        $t = $(table).find('tfoot tr').children().removeClass(css.join(' ')); 
     485                                // remove all header information 
     486                                c.$headers.removeClass(css.join(' ')); 
     487                                l = list.length; 
     488                                for (i = 0; i < l; i++) { 
     489                                        // direction = 2 means reset! 
     490                                        if (list[i][1] !== 2) { 
     491                                                // multicolumn sorting updating - choose the :last in case there are nested columns 
     492                                                f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (l === 1 ? ':last' : '') ); 
     493                                                if (f.length) { 
     494                                                        for (j = 0; j < f.length; j++) { 
     495                                                                if (!f[j].sortDisabled) { 
     496                                                                        f.eq(j).addClass(css[list[i][1]]); 
     497                                                                        // add sorted class to footer, if it exists 
     498                                                                        if ($t.length) { 
     499                                                                                $t.filter('[data-column="' + list[i][0] + '"]').eq(j).addClass(css[list[i][1]]); 
     500                                                                        } 
     501                                                                } 
     502                                                        } 
     503                                                } 
     504                                        } 
     505                                } 
     506                        } 
     507 
     508                        // automatically add col group, and column sizes if set 
     509                        function fixColumnWidth(table) { 
     510                                if (table.config.widthFixed && $(table).find('colgroup').length === 0) { 
     511                                        var colgroup = $('<colgroup>'), 
     512                                                overallWidth = $(table).width(); 
     513                                        // only add col for visible columns - fixes #371 
     514                                        $(table.tBodies[0]).find("tr:first").children("td:visible").each(function() { 
     515                                                colgroup.append($('<col>').css('width', parseInt(($(this).width()/overallWidth)*1000, 10)/10 + '%')); 
     516                                        }); 
     517                                        $(table).prepend(colgroup); 
     518                                } 
     519                        } 
     520 
     521                        function updateHeaderSortCount(table, list) { 
     522                                var s, t, o, c = table.config, 
     523                                        sl = list || c.sortList; 
     524                                c.sortList = []; 
     525                                $.each(sl, function(i,v){ 
     526                                        // ensure all sortList values are numeric - fixes #127 
     527                                        s = [ parseInt(v[0], 10), parseInt(v[1], 10) ]; 
     528                                        // make sure header exists 
     529                                        o = c.$headers[s[0]]; 
     530                                        if (o) { // prevents error if sorton array is wrong 
     531                                                c.sortList.push(s); 
     532                                                t = $.inArray(s[1], o.order); // fixes issue #167 
     533                                                o.count = t >= 0 ? t : s[1] % (c.sortReset ? 3 : 2); 
     534                                        } 
     535                                }); 
     536                        } 
     537 
     538                        function getCachedSortType(parsers, i) { 
     539                                return (parsers && parsers[i]) ? parsers[i].type || '' : ''; 
     540                        } 
     541 
     542                        function initSort(table, cell, e){ 
     543                                var a, i, j, o, s, 
     544                                        c = table.config, 
     545                                        k = !e[c.sortMultiSortKey], 
     546                                        $this = $(table); 
     547                                // Only call sortStart if sorting is enabled 
     548                                $this.trigger("sortStart", table); 
     549                                // get current column sort order 
     550                                cell.count = e[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2); 
     551                                // reset all sorts on non-current column - issue #30 
     552                                if (c.sortRestart) { 
     553                                        i = cell; 
     554                                        c.$headers.each(function() { 
     555                                                // only reset counts on columns that weren't just clicked on and if not included in a multisort 
     556                                                if (this !== i && (k || !$(this).is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc))) { 
     557                                                        this.count = -1; 
     558                                                } 
     559                                        }); 
     560                                } 
     561                                // get current column index 
     562                                i = cell.column; 
     563                                // user only wants to sort on one column 
     564                                if (k) { 
     565                                        // flush the sort list 
     566                                        c.sortList = []; 
     567                                        if (c.sortForce !== null) { 
     568                                                a = c.sortForce; 
     569                                                for (j = 0; j < a.length; j++) { 
     570                                                        if (a[j][0] !== i) { 
     571                                                                c.sortList.push(a[j]); 
     572                                                        } 
     573                                                } 
     574                                        } 
     575                                        // add column to sort list 
     576                                        o = cell.order[cell.count]; 
     577                                        if (o < 2) { 
     578                                                c.sortList.push([i, o]); 
     579                                                // add other columns if header spans across multiple 
     580                                                if (cell.colSpan > 1) { 
     581                                                        for (j = 1; j < cell.colSpan; j++) { 
     582                                                                c.sortList.push([i + j, o]); 
     583                                                        } 
     584                                                } 
     585                                        } 
     586                                        // multi column sorting 
     587                                } else { 
     588                                        // get rid of the sortAppend before adding more - fixes issue #115 
     589                                        if (c.sortAppend && c.sortList.length > 1) { 
     590                                                if (ts.isValueInArray(c.sortAppend[0][0], c.sortList)) { 
     591                                                        c.sortList.pop(); 
     592                                                } 
     593                                        } 
     594                                        // the user has clicked on an already sorted column 
     595                                        if (ts.isValueInArray(i, c.sortList)) { 
     596                                                // reverse the sorting direction 
     597                                                for (j = 0; j < c.sortList.length; j++) { 
     598                                                        s = c.sortList[j]; 
     599                                                        o = c.$headers[s[0]]; 
     600                                                        if (s[0] === i) { 
     601                                                                // o.count seems to be incorrect when compared to cell.count 
     602                                                                s[1] = o.order[cell.count]; 
     603                                                                if (s[1] === 2) { 
     604                                                                        c.sortList.splice(j,1); 
     605                                                                        o.count = -1; 
     606                                                                } 
     607                                                        } 
     608                                                } 
     609                                        } else { 
     610                                                // add column to sort list array 
     611                                                o = cell.order[cell.count]; 
     612                                                if (o < 2) { 
     613                                                        c.sortList.push([i, o]); 
     614                                                        // add other columns if header spans across multiple 
     615                                                        if (cell.colSpan > 1) { 
     616                                                                for (j = 1; j < cell.colSpan; j++) { 
     617                                                                        c.sortList.push([i + j, o]); 
     618                                                                } 
     619                                                        } 
     620                                                } 
     621                                        } 
     622                                } 
     623                                if (c.sortAppend !== null) { 
     624                                        a = c.sortAppend; 
     625                                        for (j = 0; j < a.length; j++) { 
     626                                                if (a[j][0] !== i) { 
     627                                                        c.sortList.push(a[j]); 
     628                                                } 
     629                                        } 
     630                                } 
     631                                // sortBegin event triggered immediately before the sort 
     632                                $this.trigger("sortBegin", table); 
     633                                // setTimeout needed so the processing icon shows up 
     634                                setTimeout(function(){ 
     635                                        // set css for headers 
     636                                        setHeadersCss(table); 
     637                                        multisort(table); 
     638                                        appendToTable(table); 
     639                                }, 1); 
     640                        } 
     641 
     642                        // sort multiple columns 
     643                        function multisort(table) { /*jshint loopfunc:true */ 
     644                                var i, k, num, col, colMax, cache, lc, 
     645                                        order, orgOrderCol, sortTime, sort, x, y, 
     646                                        dir = 0, 
     647                                        c = table.config, 
     648                                        cts = c.textSorter || '', 
     649                                        sortList = c.sortList, 
     650                                        l = sortList.length, 
     651                                        bl = table.tBodies.length; 
     652                                if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346 
     653                                        return; 
     654                                } 
     655                                if (c.debug) { sortTime = new Date(); } 
     656                                for (k = 0; k < bl; k++) { 
     657                                        colMax = c.cache[k].colMax; 
     658                                        cache = c.cache[k].normalized; 
     659                                        lc = cache.length; 
     660                                        orgOrderCol = (cache && cache[0]) ? cache[0].length - 1 : 0; 
     661                                        cache.sort(function(a, b) { 
     662                                                // cache is undefined here in IE, so don't use it! 
     663                                                for (i = 0; i < l; i++) { 
     664                                                        col = sortList[i][0]; 
     665                                                        order = sortList[i][1]; 
     666                                                        // sort direction, true = asc, false = desc 
     667                                                        dir = order === 0; 
     668 
     669                                                        if (c.sortStable && a[col] === b[col] && l === 1) { 
     670                                                                return a[orgOrderCol] - b[orgOrderCol]; 
     671                                                        } 
     672 
     673                                                        // fallback to natural sort since it is more robust 
     674                                                        num = /n/i.test(getCachedSortType(c.parsers, col)); 
     675                                                        if (num && c.strings[col]) { 
     676                                                                // sort strings in numerical columns 
     677                                                                if (typeof (c.string[c.strings[col]]) === 'boolean') { 
     678                                                                        num = (dir ? 1 : -1) * (c.string[c.strings[col]] ? -1 : 1); 
     679                                                                } else { 
     680                                                                        num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0; 
     681                                                                } 
     682                                                                // fall back to built-in numeric sort 
     683                                                                // var sort = $.tablesorter["sort" + s](table, a[c], b[c], c, colMax[c], dir); 
     684                                                                sort = c.numberSorter ? c.numberSorter(x[col], y[col], dir, colMax[col], table) : 
     685                                                                        ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table); 
     686                                                        } else { 
     687                                                                // set a & b depending on sort direction 
     688                                                                x = dir ? a : b; 
     689                                                                y = dir ? b : a; 
     690                                                                // text sort function 
     691                                                                if (typeof(cts) === 'function') { 
     692                                                                        // custom OVERALL text sorter 
     693                                                                        sort = cts(x[col], y[col], dir, col, table); 
     694                                                                } else if (typeof(cts) === 'object' && cts.hasOwnProperty(col)) { 
     695                                                                        // custom text sorter for a SPECIFIC COLUMN 
     696                                                                        sort = cts[col](x[col], y[col], dir, col, table); 
     697                                                                } else { 
     698                                                                        // fall back to natural sort 
     699                                                                        sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c); 
     700                                                                } 
     701                                                        } 
     702                                                        if (sort) { return sort; } 
     703                                                } 
     704                                                return a[orgOrderCol] - b[orgOrderCol]; 
     705                                        }); 
     706                                } 
     707                                if (c.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time", sortTime); } 
     708                        } 
     709 
     710                        function resortComplete($table, callback){ 
     711                                var c = $table[0].config; 
     712                                if (c.pager && !c.pager.ajax) { 
     713                                        $table.trigger('updateComplete'); 
     714                                } 
     715                                if (typeof callback === "function") { 
     716                                        callback($table[0]); 
     717                                } 
     718                        } 
     719 
     720                        function checkResort($table, flag, callback) { 
     721                                // don't try to resort if the table is still processing 
     722                                // this will catch spamming of the updateCell method 
     723                                if (flag !== false && !$table[0].isProcessing) { 
     724                                        $table.trigger("sorton", [$table[0].config.sortList, function(){ 
     725                                                resortComplete($table, callback); 
     726                                        }]); 
     727                                } else { 
     728                                        resortComplete($table, callback); 
     729                                } 
     730                        } 
     731 
     732                        function bindEvents(table){ 
     733                                var c = table.config, 
     734                                        $this = c.$table, 
     735                                        j, downTime; 
     736                                // apply event handling to headers 
     737                                c.$headers 
     738                                // http://stackoverflow.com/questions/5312849/jquery-find-self; 
     739                                .find(c.selectorSort).add( c.$headers.filter(c.selectorSort) ) 
     740                                .unbind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter') 
     741                                .bind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter', function(e, external) { 
     742                                        // only recognize left clicks or enter 
     743                                        if ( ((e.which || e.button) !== 1 && !/sort|keypress/.test(e.type)) || (e.type === 'keypress' && e.which !== 13) ) { 
     744                                                return; 
     745                                        } 
     746                                        // ignore long clicks (prevents resizable widget from initializing a sort) 
     747                                        if (e.type === 'mouseup' && external !== true && (new Date().getTime() - downTime > 250)) { return; } 
     748                                        // set timer on mousedown 
     749                                        if (e.type === 'mousedown') { 
     750                                                downTime = new Date().getTime(); 
     751                                                return e.target.tagName === "INPUT" ? '' : !c.cancelSelection; 
     752                                        } 
     753                                        if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } 
     754                                        // jQuery v1.2.6 doesn't have closest() 
     755                                        var $cell = /TH|TD/.test(this.tagName) ? $(this) : $(this).parents('th, td').filter(':first'), cell = $cell[0]; 
     756                                        if (!cell.sortDisabled) { 
     757                                                initSort(table, cell, e); 
     758                                        } 
     759                                }); 
     760                                if (c.cancelSelection) { 
     761                                        // cancel selection 
     762                                        c.$headers 
     763                                                .attr('unselectable', 'on') 
     764                                                .bind('selectstart', false) 
     765                                                .css({ 
     766                                                        'user-select': 'none', 
     767                                                        'MozUserSelect': 'none' // not needed for jQuery 1.8+ 
     768                                                }); 
     769                                } 
     770                                // apply easy methods that trigger bound events 
     771                                $this 
     772                                .unbind('sortReset update updateRows updateCell updateAll addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave '.split(' ').join('.tablesorter ')) 
     773                                .bind("sortReset.tablesorter", function(e){ 
     774                                        e.stopPropagation(); 
     775                                        c.sortList = []; 
     776                                        setHeadersCss(table); 
     777                                        multisort(table); 
     778                                        appendToTable(table); 
     779                                }) 
     780                                .bind("updateAll.tablesorter", function(e, resort, callback){ 
     781                                        e.stopPropagation(); 
     782                                        ts.refreshWidgets(table, true, true); 
     783                                        ts.restoreHeaders(table); 
     784                                        buildHeaders(table); 
     785                                        bindEvents(table); 
     786                                        commonUpdate(table, resort, callback); 
     787                                }) 
     788                                .bind("update.tablesorter updateRows.tablesorter", function(e, resort, callback) { 
     789                                        e.stopPropagation(); 
     790                                        // update sorting (if enabled/disabled) 
     791                                        updateHeader(table); 
     792                                        commonUpdate(table, resort, callback); 
     793                                }) 
     794                                .bind("updateCell.tablesorter", function(e, cell, resort, callback) { 
     795                                        e.stopPropagation(); 
     796                                        $this.find(c.selectorRemove).remove(); 
     797                                        // get position from the dom 
     798                                        var l, row, icell, 
     799                                        $tb = $this.find('tbody'), 
     800                                        // update cache - format: function(s, table, cell, cellIndex) 
     801                                        // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr'); 
     802                                        tbdy = $tb.index( $(cell).parents('tbody').filter(':first') ), 
     803                                        $row = $(cell).parents('tr').filter(':first'); 
     804                                        cell = $(cell)[0]; // in case cell is a jQuery object 
     805                                        // tbody may not exist if update is initialized while tbody is removed for processing 
     806                                        if ($tb.length && tbdy >= 0) { 
     807                                                row = $tb.eq(tbdy).find('tr').index( $row ); 
     808                                                icell = cell.cellIndex; 
     809                                                l = c.cache[tbdy].normalized[row].length - 1; 
     810                                                c.cache[tbdy].row[table.config.cache[tbdy].normalized[row][l]] = $row; 
     811                                                c.cache[tbdy].normalized[row][icell] = c.parsers[icell].format( getElementText(table, cell, icell), table, cell, icell ); 
     812                                                checkResort($this, resort, callback); 
     813                                        } 
     814                                }) 
     815                                .bind("addRows.tablesorter", function(e, $row, resort, callback) { 
     816                                        e.stopPropagation(); 
     817                                        if (isEmptyObject(c.cache)) { 
     818                                                // empty table, do an update instead - fixes #450 
     819                                                updateHeader(table); 
     820                                                commonUpdate(table, resort, callback); 
     821                                        } else { 
     822                                                var i, rows = $row.filter('tr').length, 
     823                                                dat = [], l = $row[0].cells.length, 
     824                                                tbdy = $this.find('tbody').index( $row.parents('tbody').filter(':first') ); 
     825                                                // fixes adding rows to an empty table - see issue #179 
     826                                                if (!c.parsers) { 
     827                                                        buildParserCache(table); 
     828                                                } 
     829                                                // add each row 
     830                                                for (i = 0; i < rows; i++) { 
     831                                                        // add each cell 
     832                                                        for (j = 0; j < l; j++) { 
     833                                                                dat[j] = c.parsers[j].format( getElementText(table, $row[i].cells[j], j), table, $row[i].cells[j], j ); 
     834                                                        } 
     835                                                        // add the row index to the end 
     836                                                        dat.push(c.cache[tbdy].row.length); 
     837                                                        // update cache 
     838                                                        c.cache[tbdy].row.push([$row[i]]); 
     839                                                        c.cache[tbdy].normalized.push(dat); 
     840                                                        dat = []; 
     841                                                } 
     842                                                // resort using current settings 
     843                                                checkResort($this, resort, callback); 
     844                                        } 
     845                                }) 
     846                                .bind("sorton.tablesorter", function(e, list, callback, init) { 
     847                                        var c = table.config; 
     848                                        e.stopPropagation(); 
     849                                        $this.trigger("sortStart", this); 
     850                                        // update header count index 
     851                                        updateHeaderSortCount(table, list); 
     852                                        // set css for headers 
     853                                        setHeadersCss(table); 
     854                                        // fixes #346 
     855                                        if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); } 
     856                                        $this.trigger("sortBegin", this); 
     857                                        // sort the table and append it to the dom 
     858                                        multisort(table); 
     859                                        appendToTable(table, init); 
     860                                        if (typeof callback === "function") { 
     861                                                callback(table); 
     862                                        } 
     863                                }) 
     864                                .bind("appendCache.tablesorter", function(e, callback, init) { 
     865                                        e.stopPropagation(); 
     866                                        appendToTable(table, init); 
     867                                        if (typeof callback === "function") { 
     868                                                callback(table); 
     869                                        } 
     870                                }) 
     871                                .bind("applyWidgetId.tablesorter", function(e, id) { 
     872                                        e.stopPropagation(); 
     873                                        ts.getWidgetById(id).format(table, c, c.widgetOptions); 
     874                                }) 
     875                                .bind("applyWidgets.tablesorter", function(e, init) { 
     876                                        e.stopPropagation(); 
     877                                        // apply widgets 
     878                                        ts.applyWidget(table, init); 
     879                                }) 
     880                                .bind("refreshWidgets.tablesorter", function(e, all, dontapply){ 
     881                                        e.stopPropagation(); 
     882                                        ts.refreshWidgets(table, all, dontapply); 
     883                                }) 
     884                                .bind("destroy.tablesorter", function(e, c, cb){ 
     885                                        e.stopPropagation(); 
     886                                        ts.destroy(table, c, cb); 
     887                                }); 
     888                        } 
     889 
     890                        /* public methods */ 
     891                        ts.construct = function(settings) { 
     892                                return this.each(function() { 
     893                                        var table = this, 
     894                                                // merge & extend config options 
     895                                                c = $.extend(true, {}, ts.defaults, settings); 
     896                                        // create a table from data (build table widget) 
     897                                        if (!table.hasInitialized && ts.buildTable && this.tagName !== 'TABLE') { 
     898                                                // return the table (in case the original target is the table's container) 
     899                                                ts.buildTable(table, c); 
     900                                        } 
     901                                        ts.setup(table, c); 
     902                                }); 
     903                        }; 
     904 
     905                        ts.setup = function(table, c) { 
     906                                // if no thead or tbody, or tablesorter is already present, quit 
     907                                if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) { 
     908                                        return c.debug ? log('stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : ''; 
     909                                } 
     910 
     911                                var k = '', 
     912                                        $this = $(table), 
     913                                        m = $.metadata; 
     914                                // initialization flag 
     915                                table.hasInitialized = false; 
     916                                // table is being processed flag 
     917                                table.isProcessing = true; 
     918                                // make sure to store the config object 
     919                                table.config = c; 
     920                                // save the settings where they read 
     921                                $.data(table, "tablesorter", c); 
     922                                if (c.debug) { $.data( table, 'startoveralltimer', new Date()); } 
     923 
     924                                // constants 
     925                                c.supportsTextContent = $('<span>x</span>')[0].textContent === 'x'; 
     926                                // removing this in version 3 (only supports jQuery 1.7+) 
     927                                c.supportsDataObject = (function(version) { 
     928                                        version[0] = parseInt(version[0], 10); 
     929                                        return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4); 
     930                                })($.fn.jquery.split(".")); 
     931                                // digit sort text location; keeping max+/- for backwards compatibility 
     932                                c.string = { 'max': 1, 'min': -1, 'max+': 1, 'max-': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false }; 
     933                                // add table theme class only if there isn't already one there 
     934                                if (!/tablesorter\-/.test($this.attr('class'))) { 
     935                                        k = (c.theme !== '' ? ' tablesorter-' + c.theme : ''); 
     936                                } 
     937                                c.$table = $this.addClass(ts.css.table + ' ' + c.tableClass + k); 
     938                                c.$tbodies = $this.children('tbody:not(.' + c.cssInfoBlock + ')'); 
     939                                c.widgetInit = {}; // keep a list of initialized widgets 
     940                                // build headers 
     941                                buildHeaders(table); 
     942                                // fixate columns if the users supplies the fixedWidth option 
     943                                // do this after theme has been applied 
     944                                fixColumnWidth(table); 
     945                                // try to auto detect column type, and store in tables config 
     946                                buildParserCache(table); 
     947                                // build the cache for the tbody cells 
     948                                // delayInit will delay building the cache until the user starts a sort 
     949                                if (!c.delayInit) { buildCache(table); } 
     950                                // bind all header events and methods 
     951                                bindEvents(table); 
     952                                // get sort list from jQuery data or metadata 
     953                                // in jQuery < 1.4, an error occurs when calling $this.data() 
     954                                if (c.supportsDataObject && typeof $this.data().sortlist !== 'undefined') { 
     955                                        c.sortList = $this.data().sortlist; 
     956                                } else if (m && ($this.metadata() && $this.metadata().sortlist)) { 
     957                                        c.sortList = $this.metadata().sortlist; 
     958                                } 
     959                                // apply widget init code 
     960                                ts.applyWidget(table, true); 
     961                                // if user has supplied a sort list to constructor 
     962                                if (c.sortList.length > 0) { 
     963                                        $this.trigger("sorton", [c.sortList, {}, !c.initWidgets]); 
     964                                } else if (c.initWidgets) { 
     965                                        // apply widget format 
     966                                        ts.applyWidget(table); 
     967                                } 
     968 
     969                                // show processesing icon 
     970                                if (c.showProcessing) { 
     971                                        $this 
     972                                        .unbind('sortBegin.tablesorter sortEnd.tablesorter') 
     973                                        .bind('sortBegin.tablesorter sortEnd.tablesorter', function(e) { 
     974                                                ts.isProcessing(table, e.type === 'sortBegin'); 
     975                                        }); 
     976                                } 
     977 
     978                                // initialized 
     979                                table.hasInitialized = true; 
     980                                table.isProcessing = false; 
     981                                if (c.debug) { 
     982                                        ts.benchmark("Overall initialization time", $.data( table, 'startoveralltimer')); 
     983                                } 
     984                                $this.trigger('tablesorter-initialized', table); 
     985                                if (typeof c.initialized === 'function') { c.initialized(table); } 
     986                        }; 
     987 
     988                        // *** Process table *** 
     989                        // add processing indicator 
     990                        ts.isProcessing = function(table, toggle, $ths) { 
     991                                table = $(table); 
     992                                var c = table[0].config, 
     993                                        // default to all headers 
     994                                        $h = $ths || table.find('.' + ts.css.header); 
     995                                if (toggle) { 
     996                                        if (c.sortList.length > 0) { 
     997                                                // get headers from the sortList 
     998                                                $h = $h.filter(function(){ 
     999                                                        // get data-column from attr to keep  compatibility with jQuery 1.2.6 
     1000                                                        return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList); 
     1001                                                }); 
     1002                                        } 
     1003                                        $h.addClass(ts.css.processing + ' ' + c.cssProcessing); 
     1004                                } else { 
     1005                                        $h.removeClass(ts.css.processing + ' ' + c.cssProcessing); 
     1006                                } 
     1007                        }; 
     1008 
     1009                        // detach tbody but save the position 
     1010                        // don't use tbody because there are portions that look for a tbody index (updateCell) 
     1011                        ts.processTbody = function(table, $tb, getIt){ 
     1012                                var holdr; 
     1013                                if (getIt) { 
     1014                                        table.isProcessing = true; 
     1015                                        $tb.before('<span class="tablesorter-savemyplace"/>'); 
     1016                                        holdr = ($.fn.detach) ? $tb.detach() : $tb.remove(); 
     1017                                        return holdr; 
     1018                                } 
     1019                                holdr = $(table).find('span.tablesorter-savemyplace'); 
     1020                                $tb.insertAfter( holdr ); 
     1021                                holdr.remove(); 
     1022                                table.isProcessing = false; 
     1023                        }; 
     1024 
     1025                        ts.clearTableBody = function(table) { 
     1026                                $(table)[0].config.$tbodies.empty(); 
     1027                        }; 
     1028 
     1029                        // restore headers 
     1030                        ts.restoreHeaders = function(table){ 
     1031                                var c = table.config; 
     1032                                // don't use c.$headers here in case header cells were swapped 
     1033                                c.$table.find(c.selectorHeaders).each(function(i){ 
     1034                                        // only restore header cells if it is wrapped 
     1035                                        // because this is also used by the updateAll method 
     1036                                        if ($(this).find('.tablesorter-header-inner').length){ 
     1037                                                $(this).html( c.headerContent[i] ); 
     1038                                        } 
     1039                                }); 
     1040                        }; 
     1041 
     1042                        ts.destroy = function(table, removeClasses, callback){ 
     1043                                table = $(table)[0]; 
     1044                                if (!table.hasInitialized) { return; } 
     1045                                // remove all widgets 
     1046                                ts.refreshWidgets(table, true, true); 
     1047                                var $t = $(table), c = table.config, 
     1048                                $h = $t.find('thead:first'), 
     1049                                $r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow), 
     1050                                $f = $t.find('tfoot:first > tr').children('th, td'); 
     1051                                // remove widget added rows, just in case 
     1052                                $h.find('tr').not($r).remove(); 
     1053                                // disable tablesorter 
     1054                                $t 
     1055                                        .removeData('tablesorter') 
     1056                                        .unbind('sortReset update updateAll updateRows updateCell addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd '.split(' ').join('.tablesorter ')); 
     1057                                c.$headers.add($f) 
     1058                                        .removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc].join(' ') ) 
     1059                                        .removeAttr('data-column'); 
     1060                                $r.find(c.selectorSort).unbind('mousedown.tablesorter mouseup.tablesorter keypress.tablesorter'); 
     1061                                ts.restoreHeaders(table); 
     1062                                if (removeClasses !== false) { 
     1063                                        $t.removeClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme); 
     1064                                } 
     1065                                // clear flag in case the plugin is initialized again 
     1066                                table.hasInitialized = false; 
     1067                                if (typeof callback === 'function') { 
     1068                                        callback(table); 
     1069                                } 
     1070                        }; 
     1071 
     1072                        // *** sort functions *** 
     1073                        // regex used in natural sort 
     1074                        ts.regex = { 
     1075                                chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters 
     1076                                hex: /^0x[0-9a-f]+$/i // hex 
     1077                        }; 
     1078 
     1079                        // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed) 
     1080                        ts.sortNatural = function(a, b) { 
     1081                                if (a === b) { return 0; } 
     1082                                var xN, xD, yN, yD, xF, yF, i, mx, 
     1083                                        r = ts.regex; 
     1084                                // first try and sort Hex codes 
     1085                                if (r.hex.test(b)) { 
     1086                                        xD = parseInt(a.match(r.hex), 16); 
     1087                                        yD = parseInt(b.match(r.hex), 16); 
     1088                                        if ( xD < yD ) { return -1; } 
     1089                                        if ( xD > yD ) { return 1; } 
     1090                                } 
     1091 
     1092                                // chunk/tokenize 
     1093                                xN = a.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); 
     1094                                yN = b.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); 
     1095                                mx = Math.max(xN.length, yN.length); 
     1096                                // natural sorting through split numeric strings and default strings 
     1097                                for (i = 0; i < mx; i++) { 
     1098                                        // find floats not starting with '0', string or 0 if not defined 
     1099                                        xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0; 
     1100                                        yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0; 
     1101                                        // handle numeric vs string comparison - number < string - (Kyle Adams) 
     1102                                        if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; } 
     1103                                        // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' 
     1104                                        if (typeof xF !== typeof yF) { 
     1105                                                xF += ''; 
     1106                                                yF += ''; 
     1107                                        } 
     1108                                        if (xF < yF) { return -1; } 
     1109                                        if (xF > yF) { return 1; } 
     1110                                } 
     1111                                return 0; 
     1112                        }; 
     1113 
     1114                        ts.sortNaturalAsc = function(a, b, col, table, c) { 
     1115                                if (a === b) { return 0; } 
     1116                                var e = c.string[ (c.empties[col] || c.emptyTo ) ]; 
     1117                                if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } 
     1118                                if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } 
     1119                                return ts.sortNatural(a, b); 
     1120                        }; 
     1121 
     1122                        ts.sortNaturalDesc = function(a, b, col, table, c) { 
     1123                                if (a === b) { return 0; } 
     1124                                var e = c.string[ (c.empties[col] || c.emptyTo ) ]; 
     1125                                if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } 
     1126                                if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } 
     1127                                return ts.sortNatural(b, a); 
     1128                        }; 
     1129 
     1130                        // basic alphabetical sort 
     1131                        ts.sortText = function(a, b) { 
     1132                                return a > b ? 1 : (a < b ? -1 : 0); 
     1133                        }; 
     1134 
     1135                        // return text string value by adding up ascii value 
     1136                        // so the text is somewhat sorted when using a digital sort 
     1137                        // this is NOT an alphanumeric sort 
     1138                        ts.getTextValue = function(a, num, mx) { 
     1139                                if (mx) { 
     1140                                        // make sure the text value is greater than the max numerical value (mx) 
     1141                                        var i, l = a ? a.length : 0, n = mx + num; 
     1142                                        for (i = 0; i < l; i++) { 
     1143                                                n += a.charCodeAt(i); 
     1144                                        } 
     1145                                        return num * n; 
     1146                                } 
     1147                                return 0; 
     1148                        }; 
     1149 
     1150                        ts.sortNumericAsc = function(a, b, num, mx, col, table) { 
     1151                                if (a === b) { return 0; } 
     1152                                var c = table.config, 
     1153                                        e = c.string[ (c.empties[col] || c.emptyTo ) ]; 
     1154                                if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } 
     1155                                if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } 
     1156                                if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } 
     1157                                if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } 
     1158                                return a - b; 
     1159                        }; 
     1160 
     1161                        ts.sortNumericDesc = function(a, b, num, mx, col, table) { 
     1162                                if (a === b) { return 0; } 
     1163                                var c = table.config, 
     1164                                        e = c.string[ (c.empties[col] || c.emptyTo ) ]; 
     1165                                if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } 
     1166                                if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } 
     1167                                if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } 
     1168                                if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } 
     1169                                return b - a; 
     1170                        }; 
     1171 
     1172                        ts.sortNumeric = function(a, b) { 
     1173                                return a - b; 
     1174                        }; 
     1175 
     1176                        // used when replacing accented characters during sorting 
     1177                        ts.characterEquivalents = { 
     1178                                "a" : "\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5", // áàâãäąå 
     1179                                "A" : "\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5", // ÁÀÂÃÄĄÅ 
     1180                                "c" : "\u00e7\u0107\u010d", // çćč 
     1181                                "C" : "\u00c7\u0106\u010c", // ÇĆČ 
     1182                                "e" : "\u00e9\u00e8\u00ea\u00eb\u011b\u0119", // éèêëěę 
     1183                                "E" : "\u00c9\u00c8\u00ca\u00cb\u011a\u0118", // ÉÈÊËĚĘ 
     1184                                "i" : "\u00ed\u00ec\u0130\u00ee\u00ef\u0131", // íìİîïı 
     1185                                "I" : "\u00cd\u00cc\u0130\u00ce\u00cf", // ÍÌİÎÏ 
     1186                                "o" : "\u00f3\u00f2\u00f4\u00f5\u00f6", // óòôõö 
     1187                                "O" : "\u00d3\u00d2\u00d4\u00d5\u00d6", // ÓÒÔÕÖ 
     1188                                "ss": "\u00df", // ß (s sharp) 
     1189                                "SS": "\u1e9e", // ẞ (Capital sharp s) 
     1190                                "u" : "\u00fa\u00f9\u00fb\u00fc\u016f", // úùûüů 
     1191                                "U" : "\u00da\u00d9\u00db\u00dc\u016e" // ÚÙÛÜŮ 
     1192                        }; 
     1193                        ts.replaceAccents = function(s) { 
     1194                                var a, acc = '[', eq = ts.characterEquivalents; 
     1195                                if (!ts.characterRegex) { 
     1196                                        ts.characterRegexArray = {}; 
     1197                                        for (a in eq) { 
     1198                                                if (typeof a === 'string') { 
     1199                                                        acc += eq[a]; 
     1200                                                        ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g'); 
     1201                                                } 
     1202                                        } 
     1203                                        ts.characterRegex = new RegExp(acc + ']'); 
     1204                                } 
     1205                                if (ts.characterRegex.test(s)) { 
     1206                                        for (a in eq) { 
     1207                                                if (typeof a === 'string') { 
     1208                                                        s = s.replace( ts.characterRegexArray[a], a ); 
     1209                                                } 
     1210                                        } 
     1211                                } 
     1212                                return s; 
     1213                        }; 
     1214 
     1215                        // *** utilities *** 
     1216                        ts.isValueInArray = function(v, a) { 
     1217                                var i, l = a.length; 
     1218                                for (i = 0; i < l; i++) { 
     1219                                        if (a[i][0] === v) { 
     1220                                                return true; 
     1221                                        } 
     1222                                } 
     1223                                return false; 
     1224                        }; 
     1225 
     1226                        ts.addParser = function(parser) { 
     1227                                var i, l = ts.parsers.length, a = true; 
     1228                                for (i = 0; i < l; i++) { 
     1229                                        if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) { 
     1230                                                a = false; 
     1231                                        } 
     1232                                } 
     1233                                if (a) { 
     1234                                        ts.parsers.push(parser); 
     1235                                } 
     1236                        }; 
     1237 
     1238                        ts.getParserById = function(name) { 
     1239                                var i, l = ts.parsers.length; 
     1240                                for (i = 0; i < l; i++) { 
     1241                                        if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) { 
     1242                                                return ts.parsers[i]; 
     1243                                        } 
     1244                                } 
     1245                                return false; 
     1246                        }; 
     1247 
     1248                        ts.addWidget = function(widget) { 
     1249                                ts.widgets.push(widget); 
     1250                        }; 
     1251 
     1252                        ts.getWidgetById = function(name) { 
     1253                                var i, w, l = ts.widgets.length; 
     1254                                for (i = 0; i < l; i++) { 
     1255                                        w = ts.widgets[i]; 
     1256                                        if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) { 
     1257                                                return w; 
     1258                                        } 
     1259                                } 
     1260                        }; 
     1261 
     1262                        ts.applyWidget = function(table, init) { 
     1263                                table = $(table)[0]; // in case this is called externally 
     1264                                var c = table.config, 
     1265                                        wo = c.widgetOptions, 
     1266                                        widgets = [], 
     1267                                        time, w, wd; 
     1268                                if (c.debug) { time = new Date(); } 
     1269                                if (c.widgets.length) { 
     1270                                        // ensure unique widget ids 
     1271                                        c.widgets = $.grep(c.widgets, function(v, k){ 
     1272                                                return $.inArray(v, c.widgets) === k; 
     1273                                        }); 
     1274                                        // build widget array & add priority as needed 
     1275                                        $.each(c.widgets || [], function(i,n){ 
     1276                                                wd = ts.getWidgetById(n); 
     1277                                                if (wd && wd.id) { 
     1278                                                        // set priority to 10 if not defined 
     1279                                                        if (!wd.priority) { wd.priority = 10; } 
     1280                                                        widgets[i] = wd; 
     1281                                                } 
     1282                                        }); 
     1283                                        // sort widgets by priority 
     1284                                        widgets.sort(function(a, b){ 
     1285                                                return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; 
     1286                                        }); 
     1287                                        // add/update selected widgets 
     1288                                        $.each(widgets, function(i,w){ 
     1289                                                if (w) { 
     1290                                                        if (init || !(c.widgetInit[w.id])) { 
     1291                                                                if (w.hasOwnProperty('options')) { 
     1292                                                                        wo = table.config.widgetOptions = $.extend( true, {}, w.options, wo ); 
     1293                                                                } 
     1294                                                                if (w.hasOwnProperty('init')) { 
     1295                                                                        w.init(table, w, c, wo); 
     1296                                                                } 
     1297                                                                c.widgetInit[w.id] = true; 
     1298                                                        } 
     1299                                                        if (!init && w.hasOwnProperty('format')) { 
     1300                                                                w.format(table, c, wo, false); 
     1301                                                        } 
     1302                                                } 
     1303                                        }); 
     1304                                } 
     1305                                if (c.debug) { 
     1306                                        w = c.widgets.length; 
     1307                                        benchmark("Completed " + (init === true ? "initializing " : "applying ") + w + " widget" + (w !== 1 ? "s" : ""), time); 
     1308                                } 
     1309                        }; 
     1310 
     1311                        ts.refreshWidgets = function(table, doAll, dontapply) { 
     1312                                table = $(table)[0]; // see issue #243 
     1313                                var i, c = table.config, 
     1314                                        cw = c.widgets, 
     1315                                        w = ts.widgets, l = w.length; 
     1316                                // remove previous widgets 
     1317                                for (i = 0; i < l; i++){ 
     1318                                        if ( w[i] && w[i].id && (doAll || $.inArray( w[i].id, cw ) < 0) ) { 
     1319                                                if (c.debug) { log( 'Refeshing widgets: Removing ' + w[i].id  ); } 
     1320                                                // only remove widgets that have been initialized - fixes #442 
     1321                                                if (w[i].hasOwnProperty('remove') && c.widgetInit[w[i].id]) { 
     1322                                                        w[i].remove(table, c, c.widgetOptions); 
     1323                                                        c.widgetInit[w[i].id] = false; 
     1324                                                } 
     1325                                        } 
     1326                                } 
     1327                                if (dontapply !== true) { 
     1328                                        ts.applyWidget(table, doAll); 
     1329                                } 
     1330                        }; 
     1331 
     1332                        // get sorter, string, empty, etc options for each column from 
     1333                        // jQuery data, metadata, header option or header class name ("sorter-false") 
     1334                        // priority = jQuery data > meta > headers option > header class name 
     1335                        ts.getData = function(h, ch, key) { 
     1336                                var val = '', $h = $(h), m, cl; 
     1337                                if (!$h.length) { return ''; } 
     1338                                m = $.metadata ? $h.metadata() : false; 
     1339                                cl = ' ' + ($h.attr('class') || ''); 
     1340                                if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){ 
     1341                                        // "data-lockedOrder" is assigned to "lockedorder"; but "data-locked-order" is assigned to "lockedOrder" 
     1342                                        // "data-sort-initial-order" is assigned to "sortInitialOrder" 
     1343                                        val += $h.data(key) || $h.data(key.toLowerCase()); 
     1344                                } else if (m && typeof m[key] !== 'undefined') { 
     1345                                        val += m[key]; 
     1346                                } else if (ch && typeof ch[key] !== 'undefined') { 
     1347                                        val += ch[key]; 
     1348                                } else if (cl !== ' ' && cl.match(' ' + key + '-')) { 
     1349                                        // include sorter class name "sorter-text", etc; now works with "sorter-my-custom-parser" 
     1350                                        val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || ''; 
     1351                                } 
     1352                                return $.trim(val); 
     1353                        }; 
     1354 
     1355                        ts.formatFloat = function(s, table) { 
     1356                                if (typeof s !== 'string' || s === '') { return s; } 
     1357                                // allow using formatFloat without a table; defaults to US number format 
     1358                                var i, 
     1359                                        t = table && table.config ? table.config.usNumberFormat !== false : 
     1360                                                typeof table !== "undefined" ? table : true; 
     1361                                if (t) { 
     1362                                        // US Format - 1,234,567.89 -> 1234567.89 
     1363                                        s = s.replace(/,/g,''); 
     1364                                } else { 
     1365                                        // German Format = 1.234.567,89 -> 1234567.89 
     1366                                        // French Format = 1 234 567,89 -> 1234567.89 
     1367                                        s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.'); 
     1368                                } 
     1369                                if(/^\s*\([.\d]+\)/.test(s)) { 
     1370                                        // make (#) into a negative number -> (10) = -10 
     1371                                        s = s.replace(/^\s*\(([.\d]+)\)/, '-$1'); 
     1372                                } 
     1373                                i = parseFloat(s); 
     1374                                // return the text instead of zero 
     1375                                return isNaN(i) ? $.trim(s) : i; 
     1376                        }; 
     1377 
     1378                        ts.isDigit = function(s) { 
     1379                                // replace all unwanted chars and match 
     1380                                return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : true; 
     1381                        }; 
     1382 
     1383                }() 
     1384        }); 
     1385 
     1386        // make shortcut 
     1387        var ts = $.tablesorter; 
     1388 
     1389        // extend plugin scope 
     1390        $.fn.extend({ 
     1391                tablesorter: ts.construct 
     1392        }); 
     1393 
     1394        // add default parsers 
     1395        ts.addParser({ 
     1396                id: "text", 
     1397                is: function() { 
     1398                        return true; 
     1399                }, 
     1400                format: function(s, table) { 
     1401                        var c = table.config; 
     1402                        if (s) { 
     1403                                s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s ); 
     1404                                s = c.sortLocaleCompare ? ts.replaceAccents(s) : s; 
     1405                        } 
     1406                        return s; 
     1407                }, 
     1408                type: "text" 
     1409        }); 
     1410 
     1411        ts.addParser({ 
     1412                id: "digit", 
     1413                is: function(s) { 
     1414                        return ts.isDigit(s); 
     1415                }, 
     1416                format: function(s, table) { 
     1417                        var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ""), table); 
     1418                        return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; 
     1419                }, 
     1420                type: "numeric" 
     1421        }); 
     1422 
     1423        ts.addParser({ 
     1424                id: "currency", 
     1425                is: function(s) { 
     1426                        return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[,. ]/g,'')); // £$€¤¥¢ 
     1427                }, 
     1428                format: function(s, table) { 
     1429                        var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ""), table); 
     1430                        return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; 
     1431                }, 
     1432                type: "numeric" 
     1433        }); 
     1434 
     1435        ts.addParser({ 
     1436                id: "ipAddress", 
     1437                is: function(s) { 
     1438                        return (/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/).test(s); 
     1439                }, 
     1440                format: function(s, table) { 
     1441                        var i, a = s ? s.split(".") : '', 
     1442                        r = "", 
     1443                        l = a.length; 
     1444                        for (i = 0; i < l; i++) { 
     1445                                r += ("00" + a[i]).slice(-3); 
     1446                        } 
     1447                        return s ? ts.formatFloat(r, table) : s; 
     1448                }, 
     1449                type: "numeric" 
     1450        }); 
     1451 
     1452        ts.addParser({ 
     1453                id: "url", 
     1454                is: function(s) { 
     1455                        return (/^(https?|ftp|file):\/\//).test(s); 
     1456                }, 
     1457                format: function(s) { 
     1458                        return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s; 
     1459                }, 
     1460                type: "text" 
     1461        }); 
     1462 
     1463        ts.addParser({ 
     1464                id: "isoDate", 
     1465                is: function(s) { 
     1466                        return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s); 
     1467                }, 
     1468                format: function(s, table) { 
     1469                        return s ? ts.formatFloat((s !== "") ? (new Date(s.replace(/-/g, "/")).getTime() || "") : "", table) : s; 
     1470                }, 
     1471                type: "numeric" 
     1472        }); 
     1473 
     1474        ts.addParser({ 
     1475                id: "percent", 
     1476                is: function(s) { 
     1477                        return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15; 
     1478                }, 
     1479                format: function(s, table) { 
     1480                        return s ? ts.formatFloat(s.replace(/%/g, ""), table) : s; 
     1481                }, 
     1482                type: "numeric" 
     1483        }); 
     1484 
     1485        ts.addParser({ 
     1486                id: "usLongDate", 
     1487                is: function(s) { 
     1488                        // two digit years are not allowed cross-browser 
     1489                        // Jan 01, 2013 12:34:56 PM or 01 Jan 2013 
     1490                        return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s); 
     1491                }, 
     1492                format: function(s, table) { 
     1493                        return s ? ts.formatFloat( (new Date(s.replace(/(\S)([AP]M)$/i, "$1 $2")).getTime() || ''), table) : s; 
     1494                }, 
     1495                type: "numeric" 
     1496        }); 
     1497 
     1498        ts.addParser({ 
     1499                id: "shortDate", // "mmddyyyy", "ddmmyyyy" or "yyyymmdd" 
     1500                is: function(s) { 
     1501                        // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included 
     1502                        return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g," ").replace(/[\-.,]/g, "/")); 
     1503                }, 
     1504                format: function(s, table, cell, cellIndex) { 
     1505                        if (s) { 
     1506                                var c = table.config, ci = c.headerList[cellIndex], 
     1507                                format = ci.dateFormat || ts.getData( ci, c.headers[cellIndex], 'dateFormat') || c.dateFormat; 
     1508                                s = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/"); // escaped - because JSHint in Firefox was showing it as an error 
     1509                                if (format === "mmddyyyy") { 
     1510                                        s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$1/$2"); 
     1511                                } else if (format === "ddmmyyyy") { 
     1512                                        s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1"); 
     1513                                } else if (format === "yyyymmdd") { 
     1514                                        s = s.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, "$1/$2/$3"); 
     1515                                } 
     1516                        } 
     1517                        return s ? ts.formatFloat( (new Date(s).getTime() || ''), table) : s; 
     1518                }, 
     1519                type: "numeric" 
     1520        }); 
     1521 
     1522        ts.addParser({ 
     1523                id: "time", 
     1524                is: function(s) { 
     1525                        return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s); 
     1526                }, 
     1527                format: function(s, table) { 
     1528                        return s ? ts.formatFloat( (new Date("2000/01/01 " + s.replace(/(\S)([AP]M)$/i, "$1 $2")).getTime() || ""), table) : s; 
     1529                }, 
     1530                type: "numeric" 
     1531        }); 
     1532 
     1533        ts.addParser({ 
     1534                id: "metadata", 
     1535                is: function() { 
     1536                        return false; 
     1537                }, 
     1538                format: function(s, table, cell) { 
     1539                        var c = table.config, 
     1540                        p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; 
     1541                        return $(cell).metadata()[p]; 
     1542                }, 
     1543                type: "numeric" 
     1544        }); 
     1545 
     1546        // add default widgets 
     1547        ts.addWidget({ 
     1548                id: "zebra", 
     1549                priority: 90, 
     1550                format: function(table, c, wo) { 
     1551                        var $tb, $tv, $tr, row, even, time, k, l, 
     1552                        child = new RegExp(c.cssChildRow, 'i'), 
     1553                        b = c.$tbodies; 
     1554                        if (c.debug) { 
     1555                                time = new Date(); 
     1556                        } 
     1557                        for (k = 0; k < b.length; k++ ) { 
     1558                                // loop through the visible rows 
     1559                                $tb = b.eq(k); 
     1560                                l = $tb.children('tr').length; 
     1561                                if (l > 1) { 
     1562                                        row = 0; 
     1563                                        $tv = $tb.children('tr:visible').not(c.selectorRemove); 
     1564                                        // revered back to using jQuery each - strangely it's the fastest method 
     1565                                        /*jshint loopfunc:true */ 
     1566                                        $tv.each(function(){ 
     1567                                                $tr = $(this); 
     1568                                                // style children rows the same way the parent row was styled 
     1569                                                if (!child.test(this.className)) { row++; } 
     1570                                                even = (row % 2 === 0); 
     1571                                                $tr.removeClass(wo.zebra[even ? 1 : 0]).addClass(wo.zebra[even ? 0 : 1]); 
     1572                                        }); 
     1573                                } 
     1574                        } 
     1575                        if (c.debug) { 
     1576                                ts.benchmark("Applying Zebra widget", time); 
     1577                        } 
     1578                }, 
     1579                remove: function(table, c, wo){ 
     1580                        var k, $tb, 
     1581                                b = c.$tbodies, 
     1582                                rmv = (wo.zebra || [ "even", "odd" ]).join(' '); 
     1583                        for (k = 0; k < b.length; k++ ){ 
     1584                                $tb = $.tablesorter.processTbody(table, b.eq(k), true); // remove tbody 
     1585                                $tb.children().removeClass(rmv); 
     1586                                $.tablesorter.processTbody(table, $tb, false); // restore tbody 
     1587                        } 
     1588                } 
     1589        }); 
     1590 
    10311591})(jQuery); 
  • extensions/UserAdvManager/trunk/admin/template/js/jquery.tablesorter.min.js

    r8875 r26933  
    1  
    2 (function($){$.extend({tablesorter:new 
    3 function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,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(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}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;}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]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}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=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1 
    4 var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().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 checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;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"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}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){$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>');$("tr:first td",table.tBodies[0]).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++;}}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=(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));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);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;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}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;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.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"});ts.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"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.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"});ts.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).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery); 
     1/*! 
     2* TableSorter 2.14.4 min - Client-side table sorting with ease! 
     3* Copyright (c) 2007 Christian Bach 
     4*/ 
     5!function(g){g.extend({tablesorter:new function(){function c(){var a=1<arguments.length?Array.prototype.slice.call(arguments):arguments[0];"undefined"!==typeof console&&"undefined"!==typeof console.log?console.log(a):alert(a)}function r(a,b){c(a+" ("+((new Date).getTime()-b.getTime())+"ms)")}function k(a){for(var b in a)return!1;return!0}function p(a,b,d){if(!b)return"";var h=a.config,e=h.textExtraction,n="",n="simple"===e?h.supportsTextContent?b.textContent:g(b).text():"function"===typeof e?e(b, a,d):"object"===typeof e&&e.hasOwnProperty(d)?e[d](b,a,d):h.supportsTextContent?b.textContent:g(b).text();return g.trim(n)}function s(a){var b=a.config,d=b.$tbodies=b.$table.children("tbody:not(."+b.cssInfoBlock+")"),h,e,n,l,x,g,m,v="";if(0===d.length)return b.debug?c("*Empty table!* Not building a parser cache"):"";b.debug&&(m=new Date,c("Detecting parsers for each column"));d=d[0].rows;if(d[0])for(h=[],e=d[0].cells.length,n=0;n<e;n++){l=b.$headers.filter(":not([colspan])");l=l.add(b.$headers.filter('[colspan="1"]')).filter('[data-column="'+ n+'"]:last');x=b.headers[n];g=f.getParserById(f.getData(l,x,"sorter"));b.empties[n]=f.getData(l,x,"empty")||b.emptyTo||(b.emptyToBottom?"bottom":"top");b.strings[n]=f.getData(l,x,"string")||b.stringTo||"max";if(!g)a:{l=a;x=d;g=-1;for(var k=n,u=void 0,A=f.parsers.length,q=!1,s="",u=!0;""===s&&u;)g++,x[g]?(q=x[g].cells[k],s=p(l,q,k),l.config.debug&&c("Checking if value was empty on row "+g+", column: "+k+': "'+s+'"')):u=!1;for(;0<=--A;)if((u=f.parsers[A])&&"text"!==u.id&&u.is&&u.is(s,l,q)){g=u;break a}g= f.getParserById("text")}b.debug&&(v+="column:"+n+"; parser:"+g.id+"; string:"+b.strings[n]+"; empty: "+b.empties[n]+"\n");h.push(g)}b.debug&&(c(v),r("Completed detecting parsers",m));b.parsers=h}function w(a){var b=a.tBodies,d=a.config,h,e,n=d.parsers,l,x,y,m,v,k,u,A=[];d.cache={};if(!n)return d.debug?c("*Empty table!* Not building a cache"):"";d.debug&&(u=new Date);d.showProcessing&&f.isProcessing(a,!0);for(m=0;m<b.length;m++)if(d.cache[m]={row:[],normalized:[]},!g(b[m]).hasClass(d.cssInfoBlock)){h= b[m]&&b[m].rows.length||0;e=b[m].rows[0]&&b[m].rows[0].cells.length||0;for(x=0;x<h;++x)if(v=g(b[m].rows[x]),k=[],v.hasClass(d.cssChildRow))d.cache[m].row[d.cache[m].row.length-1]=d.cache[m].row[d.cache[m].row.length-1].add(v);else{d.cache[m].row.push(v);for(y=0;y<e;++y)l=p(a,v[0].cells[y],y),l=n[y].format(l,a,v[0].cells[y],y),k.push(l),"numeric"===(n[y].type||"").toLowerCase()&&(A[y]=Math.max(Math.abs(l)||0,A[y]||0));k.push(d.cache[m].normalized.length);d.cache[m].normalized.push(k)}d.cache[m].colMax= A}d.showProcessing&&f.isProcessing(a);d.debug&&r("Building cache for "+h+" rows",u)}function z(a,b){var d=a.config,h=d.widgetOptions,e=a.tBodies,n=[],l=d.cache,c,y,m,v,p,u,A,q,s,t,w;if(!k(l)){d.debug&&(w=new Date);for(q=0;q<e.length;q++)if(c=g(e[q]),c.length&&!c.hasClass(d.cssInfoBlock)){p=f.processTbody(a,c,!0);c=l[q].row;y=l[q].normalized;v=(m=y.length)?y[0].length-1:0;for(u=0;u<m;u++)if(t=y[u][v],n.push(c[t]),!d.appender||d.pager&&!(d.pager.removeRows&&h.pager_removeRows||d.pager.ajax))for(s=c[t].length, A=0;A<s;A++)p.append(c[t][A]);f.processTbody(a,p,!1)}d.appender&&d.appender(a,n);d.debug&&r("Rebuilt table",w);b||d.appender||f.applyWidget(a);g(a).trigger("sortEnd",a);g(a).trigger("updateComplete",a)}}function D(a){var b=[],d={},h=0,e=g(a).find("thead:eq(0), tfoot").children("tr"),n,l,c,f,m,k,r,p,t,q;for(n=0;n<e.length;n++)for(m=e[n].cells,l=0;l<m.length;l++){f=m[l];k=f.parentNode.rowIndex;r=k+"-"+f.cellIndex;p=f.rowSpan||1;t=f.colSpan||1;"undefined"===typeof b[k]&&(b[k]=[]);for(c=0;c<b[k].length+ 1;c++)if("undefined"===typeof b[k][c]){q=c;break}d[r]=q;h=Math.max(q,h);g(f).attr({"data-column":q});for(c=k;c<k+p;c++)for("undefined"===typeof b[c]&&(b[c]=[]),r=b[c],f=q;f<q+t;f++)r[f]="x"}a.config.columns=h+1;return d}function C(a){return/^d/i.test(a)||1===a}function E(a){var b=D(a),d,h,e,n,l,x,k,m=a.config;m.headerList=[];m.headerContent=[];m.debug&&(k=new Date);n=m.cssIcon?'<i class="'+(m.cssIcon===f.css.icon?f.css.icon:m.cssIcon+" "+f.css.icon)+'"></i>':"";m.$headers=g(a).find(m.selectorHeaders).each(function(a){h= g(this);d=m.headers[a];m.headerContent[a]=g(this).html();l=m.headerTemplate.replace(/\{content\}/g,g(this).html()).replace(/\{icon\}/g,n);m.onRenderTemplate&&(e=m.onRenderTemplate.apply(h,[a,l]))&&"string"===typeof e&&(l=e);g(this).html('<div class="tablesorter-header-inner">'+l+"</div>");m.onRenderHeader&&m.onRenderHeader.apply(h,[a]);this.column=b[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=C(f.getData(h,d,"sortInitialOrder")||m.sortInitialOrder)?[1,0,2]:[0,1,2];this.count=-1;this.lockedOrder= !1;x=f.getData(h,d,"lockedOrder")||!1;"undefined"!==typeof x&&!1!==x&&(this.order=this.lockedOrder=C(x)?[1,1,1]:[0,0,0]);h.addClass(f.css.header+" "+m.cssHeader);m.headerList[a]=this;h.parent().addClass(f.css.headerRow+" "+m.cssHeaderRow);m.tabIndex&&h.attr("tabindex",0)});F(a);m.debug&&(r("Built headers:",k),c(m.$headers))}function B(a,b,d){var h=a.config;h.$table.find(h.selectorRemove).remove();s(a);w(a);G(h.$table,b,d)}function F(a){var b,d=a.config;d.$headers.each(function(a,e){b="false"===f.getData(e, d.headers[a],"sorter");e.sortDisabled=b;g(e)[b?"addClass":"removeClass"]("sorter-false")})}function H(a){var b,d,h,e=a.config,n=e.sortList,l=[f.css.sortAsc+" "+e.cssAsc,f.css.sortDesc+" "+e.cssDesc],c=g(a).find("tfoot tr").children().removeClass(l.join(" "));e.$headers.removeClass(l.join(" "));h=n.length;for(b=0;b<h;b++)if(2!==n[b][1]&&(a=e.$headers.not(".sorter-false").filter('[data-column="'+n[b][0]+'"]'+(1===h?":last":"")),a.length))for(d=0;d<a.length;d++)a[d].sortDisabled||(a.eq(d).addClass(l[n[b][1]]), c.length&&c.filter('[data-column="'+n[b][0]+'"]').eq(d).addClass(l[n[b][1]]))}function L(a){if(a.config.widthFixed&&0===g(a).find("colgroup").length){var b=g("<colgroup>"),d=g(a).width();g(a.tBodies[0]).find("tr:first").children("td:visible").each(function(){b.append(g("<col>").css("width",parseInt(g(this).width()/d*1E3,10)/10+"%"))});g(a).prepend(b)}}function M(a,b){var d,h,e,n=a.config,c=b||n.sortList;n.sortList=[];g.each(c,function(a,b){d=[parseInt(b[0],10),parseInt(b[1],10)];if(e=n.$headers[d[0]])n.sortList.push(d), h=g.inArray(d[1],e.order),e.count=0<=h?h:d[1]%(n.sortReset?3:2)})}function N(a,b){return a&&a[b]?a[b].type||"":""}function O(a,b,d){var h,e,n,c=a.config,x=!d[c.sortMultiSortKey],k=g(a);k.trigger("sortStart",a);b.count=d[c.sortResetKey]?2:(b.count+1)%(c.sortReset?3:2);c.sortRestart&&(e=b,c.$headers.each(function(){this===e||!x&&g(this).is("."+f.css.sortDesc+",."+f.css.sortAsc)||(this.count=-1)}));e=b.column;if(x){c.sortList=[];if(null!==c.sortForce)for(h=c.sortForce,d=0;d<h.length;d++)h[d][0]!==e&& c.sortList.push(h[d]);h=b.order[b.count];if(2>h&&(c.sortList.push([e,h]),1<b.colSpan))for(d=1;d<b.colSpan;d++)c.sortList.push([e+d,h])}else if(c.sortAppend&&1<c.sortList.length&&f.isValueInArray(c.sortAppend[0][0],c.sortList)&&c.sortList.pop(),f.isValueInArray(e,c.sortList))for(d=0;d<c.sortList.length;d++)n=c.sortList[d],h=c.$headers[n[0]],n[0]===e&&(n[1]=h.order[b.count],2===n[1]&&(c.sortList.splice(d,1),h.count=-1));else if(h=b.order[b.count],2>h&&(c.sortList.push([e,h]),1<b.colSpan))for(d=1;d< b.colSpan;d++)c.sortList.push([e+d,h]);if(null!==c.sortAppend)for(h=c.sortAppend,d=0;d<h.length;d++)h[d][0]!==e&&c.sortList.push(h[d]);k.trigger("sortBegin",a);setTimeout(function(){H(a);I(a);z(a)},1)}function I(a){var b,d,c,e,n,l,g,p,m,v,t,u,s=0,q=a.config,w=q.textSorter||"",z=q.sortList,B=z.length,C=a.tBodies.length;if(!q.serverSideSorting&&!k(q.cache)){q.debug&&(m=new Date);for(d=0;d<C;d++)n=q.cache[d].colMax,p=(l=q.cache[d].normalized)&&l[0]?l[0].length-1:0,l.sort(function(d,l){for(b=0;b<B;b++){e= z[b][0];g=z[b][1];s=0===g;if(q.sortStable&&d[e]===l[e]&&1===B)break;(c=/n/i.test(N(q.parsers,e)))&&q.strings[e]?(c="boolean"===typeof q.string[q.strings[e]]?(s?1:-1)*(q.string[q.strings[e]]?-1:1):q.strings[e]?q.string[q.strings[e]]||0:0,v=q.numberSorter?q.numberSorter(t[e],u[e],s,n[e],a):f["sortNumeric"+(s?"Asc":"Desc")](d[e],l[e],c,n[e],e,a)):(t=s?d:l,u=s?l:d,v="function"===typeof w?w(t[e],u[e],s,e,a):"object"===typeof w&&w.hasOwnProperty(e)?w[e](t[e],u[e],s,e,a):f["sortNatural"+(s?"Asc":"Desc")](d[e], l[e],e,a,q));if(v)return v}return d[p]-l[p]});q.debug&&r("Sorting on "+z.toString()+" and dir "+g+" time",m)}}function J(a,b){var d=a[0].config;d.pager&&!d.pager.ajax&&a.trigger("updateComplete");"function"===typeof b&&b(a[0])}function G(a,b,d){!1===b||a[0].isProcessing?J(a,d):a.trigger("sorton",[a[0].config.sortList,function(){J(a,d)}])}function K(a){var b=a.config,d=b.$table,c,e;b.$headers.find(b.selectorSort).add(b.$headers.filter(b.selectorSort)).unbind("mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter").bind("mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter", function(d,c){if(!(1!==(d.which||d.button)&&!/sort|keypress/.test(d.type)||"keypress"===d.type&&13!==d.which||"mouseup"===d.type&&!0!==c&&250<(new Date).getTime()-e)){if("mousedown"===d.type)return e=(new Date).getTime(),"INPUT"===d.target.tagName?"":!b.cancelSelection;b.delayInit&&k(b.cache)&&w(a);var h=(/TH|TD/.test(this.tagName)?g(this):g(this).parents("th, td").filter(":first"))[0];h.sortDisabled||O(a,h,d)}});b.cancelSelection&&b.$headers.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none", MozUserSelect:"none"});d.unbind("sortReset update updateRows updateCell updateAll addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(".tablesorter ")).bind("sortReset.tablesorter",function(d){d.stopPropagation();b.sortList=[];H(a);I(a);z(a)}).bind("updateAll.tablesorter",function(b,d,c){b.stopPropagation();f.refreshWidgets(a,!0,!0);f.restoreHeaders(a);E(a);K(a);B(a,d,c)}).bind("update.tablesorter updateRows.tablesorter",function(b,d,c){b.stopPropagation(); F(a);B(a,d,c)}).bind("updateCell.tablesorter",function(c,e,h,f){c.stopPropagation();d.find(b.selectorRemove).remove();var m,k,r;m=d.find("tbody");c=m.index(g(e).parents("tbody").filter(":first"));var s=g(e).parents("tr").filter(":first");e=g(e)[0];m.length&&0<=c&&(k=m.eq(c).find("tr").index(s),r=e.cellIndex,m=b.cache[c].normalized[k].length-1,b.cache[c].row[a.config.cache[c].normalized[k][m]]=s,b.cache[c].normalized[k][r]=b.parsers[r].format(p(a,e,r),a,e,r),G(d,h,f))}).bind("addRows.tablesorter", function(e,f,g,r){e.stopPropagation();if(k(b.cache))F(a),B(a,g,r);else{var m=f.filter("tr").length,v=[],w=f[0].cells.length,u=d.find("tbody").index(f.parents("tbody").filter(":first"));b.parsers||s(a);for(e=0;e<m;e++){for(c=0;c<w;c++)v[c]=b.parsers[c].format(p(a,f[e].cells[c],c),a,f[e].cells[c],c);v.push(b.cache[u].row.length);b.cache[u].row.push([f[e]]);b.cache[u].normalized.push(v);v=[]}G(d,g,r)}}).bind("sorton.tablesorter",function(b,c,e,h){var f=a.config;b.stopPropagation();d.trigger("sortStart", this);M(a,c);H(a);f.delayInit&&k(f.cache)&&w(a);d.trigger("sortBegin",this);I(a);z(a,h);"function"===typeof e&&e(a)}).bind("appendCache.tablesorter",function(b,d,c){b.stopPropagation();z(a,c);"function"===typeof d&&d(a)}).bind("applyWidgetId.tablesorter",function(d,c){d.stopPropagation();f.getWidgetById(c).format(a,b,b.widgetOptions)}).bind("applyWidgets.tablesorter",function(b,d){b.stopPropagation();f.applyWidget(a,d)}).bind("refreshWidgets.tablesorter",function(b,d,c){b.stopPropagation();f.refreshWidgets(a, d,c)}).bind("destroy.tablesorter",function(b,d,c){b.stopPropagation();f.destroy(a,d,c)})}var f=this;f.version="2.14.4";f.parsers=[];f.widgets=[];f.defaults={theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1, sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",textExtraction:"simple",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0,initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssInfoBlock:"tablesorter-infoOnly",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me", debug:!1,headerList:[],empties:{},strings:{},parsers:[]};f.css={table:"tablesorter",childRow:"tablesorter-childRow",header:"tablesorter-header",headerRow:"tablesorter-headerRow",icon:"tablesorter-icon",info:"tablesorter-infoOnly",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc"};f.log=c;f.benchmark=r;f.construct=function(a){return this.each(function(){var b=g.extend(!0,{},f.defaults,a);!this.hasInitialized&&f.buildTable&&"TABLE"!==this.tagName&& f.buildTable(this,b);f.setup(this,b)})};f.setup=function(a,b){if(!a||!a.tHead||0===a.tBodies.length||!0===a.hasInitialized)return b.debug?c("stopping initialization! No table, thead, tbody or tablesorter has already been initialized"):"";var d="",h=g(a),e=g.metadata;a.hasInitialized=!1;a.isProcessing=!0;a.config=b;g.data(a,"tablesorter",b);b.debug&&g.data(a,"startoveralltimer",new Date);b.supportsTextContent="x"===g("<span>x</span>")[0].textContent;b.supportsDataObject=function(a){a[0]=parseInt(a[0], 10);return 1<a[0]||1===a[0]&&4<=parseInt(a[1],10)}(g.fn.jquery.split("."));b.string={max:1,min:-1,"max+":1,"max-":-1,zero:0,none:0,"null":0,top:!0,bottom:!1};/tablesorter\-/.test(h.attr("class"))||(d=""!==b.theme?" tablesorter-"+b.theme:"");b.$table=h.addClass(f.css.table+" "+b.tableClass+d);b.$tbodies=h.children("tbody:not(."+b.cssInfoBlock+")");b.widgetInit={};E(a);L(a);s(a);b.delayInit||w(a);K(a);b.supportsDataObject&&"undefined"!==typeof h.data().sortlist?b.sortList=h.data().sortlist:e&&h.metadata()&& h.metadata().sortlist&&(b.sortList=h.metadata().sortlist);f.applyWidget(a,!0);0<b.sortList.length?h.trigger("sorton",[b.sortList,{},!b.initWidgets]):b.initWidgets&&f.applyWidget(a);b.showProcessing&&h.unbind("sortBegin.tablesorter sortEnd.tablesorter").bind("sortBegin.tablesorter sortEnd.tablesorter",function(b){f.isProcessing(a,"sortBegin"===b.type)});a.hasInitialized=!0;a.isProcessing=!1;b.debug&&f.benchmark("Overall initialization time",g.data(a,"startoveralltimer"));h.trigger("tablesorter-initialized", a);"function"===typeof b.initialized&&b.initialized(a)};f.isProcessing=function(a,b,d){a=g(a);var c=a[0].config;a=d||a.find("."+f.css.header);b?(0<c.sortList.length&&(a=a.filter(function(){return this.sortDisabled?!1:f.isValueInArray(parseFloat(g(this).attr("data-column")),c.sortList)})),a.addClass(f.css.processing+" "+c.cssProcessing)):a.removeClass(f.css.processing+" "+c.cssProcessing)};f.processTbody=function(a,b,d){if(d)return a.isProcessing=!0,b.before('<span class="tablesorter-savemyplace"/>'), d=g.fn.detach?b.detach():b.remove();d=g(a).find("span.tablesorter-savemyplace");b.insertAfter(d);d.remove();a.isProcessing=!1};f.clearTableBody=function(a){g(a)[0].config.$tbodies.empty()};f.restoreHeaders=function(a){var b=a.config;b.$table.find(b.selectorHeaders).each(function(a){g(this).find(".tablesorter-header-inner").length&&g(this).html(b.headerContent[a])})};f.destroy=function(a,b,d){a=g(a)[0];if(a.hasInitialized){f.refreshWidgets(a,!0,!0);var c=g(a),e=a.config,n=c.find("thead:first"),l=n.find("tr."+ f.css.headerRow).removeClass(f.css.headerRow+" "+e.cssHeaderRow),k=c.find("tfoot:first > tr").children("th, td");n.find("tr").not(l).remove();c.removeData("tablesorter").unbind("sortReset update updateAll updateRows updateCell addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd ".split(" ").join(".tablesorter "));e.$headers.add(k).removeClass([f.css.header,e.cssHeader,e.cssAsc,e.cssDesc,f.css.sortAsc,f.css.sortDesc].join(" ")).removeAttr("data-column"); l.find(e.selectorSort).unbind("mousedown.tablesorter mouseup.tablesorter keypress.tablesorter");f.restoreHeaders(a);!1!==b&&c.removeClass(f.css.table+" "+e.tableClass+" tablesorter-"+e.theme);a.hasInitialized=!1;"function"===typeof d&&d(a)}};f.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,hex:/^0x[0-9a-f]+$/i};f.sortNatural=function(a,b){if(a===b)return 0;var d,c,e,g,l,k;c=f.regex;if(c.hex.test(b)){d=parseInt(a.match(c.hex),16);e=parseInt(b.match(c.hex), 16);if(d<e)return-1;if(d>e)return 1}d=a.replace(c.chunk,"\\0$1\\0").replace(/\\0$/,"").replace(/^\\0/,"").split("\\0");c=b.replace(c.chunk,"\\0$1\\0").replace(/\\0$/,"").replace(/^\\0/,"").split("\\0");k=Math.max(d.length,c.length);for(l=0;l<k;l++){e=isNaN(d[l])?d[l]||0:parseFloat(d[l])||0;g=isNaN(c[l])?c[l]||0:parseFloat(c[l])||0;if(isNaN(e)!==isNaN(g))return isNaN(e)?1:-1;typeof e!==typeof g&&(e+="",g+="");if(e<g)return-1;if(e>g)return 1}return 0};f.sortNaturalAsc=function(a,b,d,c,e){if(a===b)return 0; d=e.string[e.empties[d]||e.emptyTo];return""===a&&0!==d?"boolean"===typeof d?d?-1:1:-d||-1:""===b&&0!==d?"boolean"===typeof d?d?1:-1:d||1:f.sortNatural(a,b)};f.sortNaturalDesc=function(a,b,d,c,e){if(a===b)return 0;d=e.string[e.empties[d]||e.emptyTo];return""===a&&0!==d?"boolean"===typeof d?d?-1:1:d||1:""===b&&0!==d?"boolean"===typeof d?d?1:-1:-d||-1:f.sortNatural(b,a)};f.sortText=function(a,b){return a>b?1:a<b?-1:0};f.getTextValue=function(a,b,d){if(d){var c=a?a.length:0,e=d+b;for(d=0;d<c;d++)e+= a.charCodeAt(d);return b*e}return 0};f.sortNumericAsc=function(a,b,d,c,e,g){if(a===b)return 0;g=g.config;e=g.string[g.empties[e]||g.emptyTo];if(""===a&&0!==e)return"boolean"===typeof e?e?-1:1:-e||-1;if(""===b&&0!==e)return"boolean"===typeof e?e?1:-1:e||1;isNaN(a)&&(a=f.getTextValue(a,d,c));isNaN(b)&&(b=f.getTextValue(b,d,c));return a-b};f.sortNumericDesc=function(a,b,d,c,e,g){if(a===b)return 0;g=g.config;e=g.string[g.empties[e]||g.emptyTo];if(""===a&&0!==e)return"boolean"===typeof e?e?-1:1:e||1;if(""=== b&&0!==e)return"boolean"===typeof e?e?1:-1:-e||-1;isNaN(a)&&(a=f.getTextValue(a,d,c));isNaN(b)&&(b=f.getTextValue(b,d,c));return b-a};f.sortNumeric=function(a,b){return a-b};f.characterEquivalents={a:"\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5",A:"\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5",c:"\u00e7\u0107\u010d",C:"\u00c7\u0106\u010c",e:"\u00e9\u00e8\u00ea\u00eb\u011b\u0119",E:"\u00c9\u00c8\u00ca\u00cb\u011a\u0118",i:"\u00ed\u00ec\u0130\u00ee\u00ef\u0131",I:"\u00cd\u00cc\u0130\u00ce\u00cf",o:"\u00f3\u00f2\u00f4\u00f5\u00f6", O:"\u00d3\u00d2\u00d4\u00d5\u00d6",ss:"\u00df",SS:"\u1e9e",u:"\u00fa\u00f9\u00fb\u00fc\u016f",U:"\u00da\u00d9\u00db\u00dc\u016e"};f.replaceAccents=function(a){var b,d="[",c=f.characterEquivalents;if(!f.characterRegex){f.characterRegexArray={};for(b in c)"string"===typeof b&&(d+=c[b],f.characterRegexArray[b]=RegExp("["+c[b]+"]","g"));f.characterRegex=RegExp(d+"]")}if(f.characterRegex.test(a))for(b in c)"string"===typeof b&&(a=a.replace(f.characterRegexArray[b],b));return a};f.isValueInArray=function(a, b){var d,c=b.length;for(d=0;d<c;d++)if(b[d][0]===a)return!0;return!1};f.addParser=function(a){var b,d=f.parsers.length,c=!0;for(b=0;b<d;b++)f.parsers[b].id.toLowerCase()===a.id.toLowerCase()&&(c=!1);c&&f.parsers.push(a)};f.getParserById=function(a){var b,d=f.parsers.length;for(b=0;b<d;b++)if(f.parsers[b].id.toLowerCase()===a.toString().toLowerCase())return f.parsers[b];return!1};f.addWidget=function(a){f.widgets.push(a)};f.getWidgetById=function(a){var b,d,c=f.widgets.length;for(b=0;b<c;b++)if((d= f.widgets[b])&&d.hasOwnProperty("id")&&d.id.toLowerCase()===a.toLowerCase())return d};f.applyWidget=function(a,b){a=g(a)[0];var d=a.config,c=d.widgetOptions,e=[],k,l,p;d.debug&&(k=new Date);d.widgets.length&&(d.widgets=g.grep(d.widgets,function(a,b){return g.inArray(a,d.widgets)===b}),g.each(d.widgets||[],function(a,b){(p=f.getWidgetById(b))&&p.id&&(p.priority||(p.priority=10),e[a]=p)}),e.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority?0:1}),g.each(e,function(e,f){if(f){if(b|| !d.widgetInit[f.id])f.hasOwnProperty("options")&&(c=a.config.widgetOptions=g.extend(!0,{},f.options,c)),f.hasOwnProperty("init")&&f.init(a,f,d,c),d.widgetInit[f.id]=!0;!b&&f.hasOwnProperty("format")&&f.format(a,d,c,!1)}}));d.debug&&(l=d.widgets.length,r("Completed "+(!0===b?"initializing ":"applying ")+l+" widget"+(1!==l?"s":""),k))};f.refreshWidgets=function(a,b,d){a=g(a)[0];var h,e=a.config,k=e.widgets,l=f.widgets,r=l.length;for(h=0;h<r;h++)l[h]&&l[h].id&&(b||0>g.inArray(l[h].id,k))&&(e.debug&& c("Refeshing widgets: Removing "+l[h].id),l[h].hasOwnProperty("remove")&&e.widgetInit[l[h].id]&&(l[h].remove(a,e,e.widgetOptions),e.widgetInit[l[h].id]=!1));!0!==d&&f.applyWidget(a,b)};f.getData=function(a,b,d){var c="";a=g(a);var e,f;if(!a.length)return"";e=g.metadata?a.metadata():!1;f=" "+(a.attr("class")||"");"undefined"!==typeof a.data(d)||"undefined"!==typeof a.data(d.toLowerCase())?c+=a.data(d)||a.data(d.toLowerCase()):e&&"undefined"!==typeof e[d]?c+=e[d]:b&&"undefined"!==typeof b[d]?c+=b[d]: " "!==f&&f.match(" "+d+"-")&&(c=f.match(RegExp("\\s"+d+"-([\\w-]+)"))[1]||"");return g.trim(c)};f.formatFloat=function(a,b){if("string"!==typeof a||""===a)return a;var c;a=(b&&b.config?!1!==b.config.usNumberFormat:"undefined"!==typeof b?b:1)?a.replace(/,/g,""):a.replace(/[\s|\.]/g,"").replace(/,/g,".");/^\s*\([.\d]+\)/.test(a)&&(a=a.replace(/^\s*\(([.\d]+)\)/,"-$1"));c=parseFloat(a);return isNaN(c)?g.trim(a):c};f.isDigit=function(a){return isNaN(a)?/^[\-+(]?\d+[)]?$/.test(a.toString().replace(/[,.'"\s]/g, "")):!0}}});var p=g.tablesorter;g.fn.extend({tablesorter:p.construct});p.addParser({id:"text",is:function(){return!0},format:function(c,r){var k=r.config;c&&(c=g.trim(k.ignoreCase?c.toLocaleLowerCase():c),c=k.sortLocaleCompare?p.replaceAccents(c):c);return c},type:"text"});p.addParser({id:"digit",is:function(c){return p.isDigit(c)},format:function(c,r){var k=p.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),r);return c&&"number"===typeof k?k:c?g.trim(c&&r.config.ignoreCase?c.toLocaleLowerCase():c): c},type:"numeric"});p.addParser({id:"currency",is:function(c){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((c||"").replace(/[,. ]/g,""))},format:function(c,r){var k=p.formatFloat((c||"").replace(/[^\w,. \-()]/g,""),r);return c&&"number"===typeof k?k:c?g.trim(c&&r.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"});p.addParser({id:"ipAddress",is:function(c){return/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/.test(c)},format:function(c, g){var k,t=c?c.split("."):"",s="",w=t.length;for(k=0;k<w;k++)s+=("00"+t[k]).slice(-3);return c?p.formatFloat(s,g):c},type:"numeric"});p.addParser({id:"url",is:function(c){return/^(https?|ftp|file):\/\//.test(c)},format:function(c){return c?g.trim(c.replace(/(https?|ftp|file):\/\//,"")):c},type:"text"});p.addParser({id:"isoDate",is:function(c){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(c)},format:function(c,g){return c?p.formatFloat(""!==c?(new Date(c.replace(/-/g,"/"))).getTime()||"":"",g):c}, type:"numeric"});p.addParser({id:"percent",is:function(c){return/(\d\s*?%|%\s*?\d)/.test(c)&&15>c.length},format:function(c,g){return c?p.formatFloat(c.replace(/%/g,""),g):c},type:"numeric"});p.addParser({id:"usLongDate",is:function(c){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(c)||/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(c)},format:function(c,g){return c?p.formatFloat((new Date(c.replace(/(\S)([AP]M)$/i,"$1 $2"))).getTime()||"",g):c},type:"numeric"}); p.addParser({id:"shortDate",is:function(c){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((c||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(c,g,k,t){if(c){k=g.config;var s=k.headerList[t];t=s.dateFormat||p.getData(s,k.headers[t],"dateFormat")||k.dateFormat;c=c.replace(/\s+/g," ").replace(/[\-.,]/g,"/");"mmddyyyy"===t?c=c.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===t?c=c.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1"):"yyyymmdd"===t&&(c=c.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3"))}return c?p.formatFloat((new Date(c)).getTime()||"",g):c},type:"numeric"});p.addParser({id:"time",is:function(c){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(c)},format:function(c,g){return c?p.formatFloat((new Date("2000/01/01 "+c.replace(/(\S)([AP]M)$/i,"$1 $2"))).getTime()||"",g):c},type:"numeric"});p.addParser({id:"metadata",is:function(){return!1},format:function(c,p,k){c=p.config; c=c.parserMetadataName?c.parserMetadataName:"sortValue";return g(k).metadata()[c]},type:"numeric"});p.addWidget({id:"zebra",priority:90,format:function(c,r,k){var t,s,w,z,D,C,E=RegExp(r.cssChildRow,"i"),B=r.$tbodies;r.debug&&(D=new Date);for(c=0;c<B.length;c++)t=B.eq(c),C=t.children("tr").length,1<C&&(w=0,t=t.children("tr:visible").not(r.selectorRemove),t.each(function(){s=g(this);E.test(this.className)||w++;z=0===w%2;s.removeClass(k.zebra[z?1:0]).addClass(k.zebra[z?0:1])}));r.debug&&p.benchmark("Applying Zebra widget", D)},remove:function(c,p,k){var t;p=p.$tbodies;var s=(k.zebra||["even","odd"]).join(" ");for(k=0;k<p.length;k++)t=g.tablesorter.processTbody(c,p.eq(k),!0),t.children().removeClass(s),g.tablesorter.processTbody(c,t,!1)}})}(jQuery); 
  • extensions/UserAdvManager/trunk/admin/template/js/jquery.tablesorter.pager.js

    r6399 r26933  
    1 (function($) { 
    2         $.extend({ 
    3                 tablesorterPager: new function() { 
    4                          
    5                         function updatePageDisplay(c) { 
    6                                 var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);    
    7                         } 
    8                          
    9                         function setPageSize(table,size) { 
    10                                 var c = table.config; 
    11                                 c.size = size; 
    12                                 c.totalPages = Math.ceil(c.totalRows / c.size); 
    13                                 c.pagerPositionSet = false; 
    14                                 moveToPage(table); 
    15                                 fixPosition(table); 
    16                         } 
    17                          
    18                         function fixPosition(table) { 
    19                                 var c = table.config; 
    20                                 if(!c.pagerPositionSet && c.positionFixed) { 
    21                                         var c = table.config, o = $(table); 
    22                                         if(o.offset) { 
    23                                                 c.container.css({ 
    24                                                         top: o.offset().top + o.height() + 'px', 
    25                                                         position: 'absolute' 
     1/*! 
     2 * tablesorter pager plugin 
     3 * updated 12/16/2013 (v2.14.5) 
     4 */ 
     5/*jshint browser:true, jquery:true, unused:false */ 
     6;(function($) { 
     7        "use strict"; 
     8        /*jshint supernew:true */ 
     9        var ts = $.tablesorter; 
     10 
     11        $.extend({ tablesorterPager: new function() { 
     12 
     13                this.defaults = { 
     14                        // target the pager markup 
     15                        container: null, 
     16 
     17                        // use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}" 
     18                        // where {page} is replaced by the page number, {size} is replaced by the number of records to show, 
     19                        // {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds 
     20                        // the filterList to the url into an "fcol" array. 
     21                        // So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url 
     22                        // and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url 
     23                        ajaxUrl: null, 
     24 
     25                        // modify the url after all processing has been applied 
     26                        customAjaxUrl: function(table, url) { return url; }, 
     27 
     28                        // modify the $.ajax object to allow complete control over your ajax requests 
     29                        ajaxObject: { 
     30                                dataType: 'json' 
     31                        }, 
     32 
     33                        // set this to false if you want to block ajax loading on init 
     34                        processAjaxOnInit: true, 
     35 
     36                        // process ajax so that the following information is returned: 
     37                        // [ total_rows (number), rows (array of arrays), headers (array; optional) ] 
     38                        // example: 
     39                        // [ 
     40                        //   100,  // total rows 
     41                        //   [ 
     42                        //     [ "row1cell1", "row1cell2", ... "row1cellN" ], 
     43                        //     [ "row2cell1", "row2cell2", ... "row2cellN" ], 
     44                        //     ... 
     45                        //     [ "rowNcell1", "rowNcell2", ... "rowNcellN" ] 
     46                        //   ], 
     47                        //   [ "header1", "header2", ... "headerN" ] // optional 
     48                        // ] 
     49                        ajaxProcessing: function(ajax){ return [ 0, [], null ]; }, 
     50 
     51                        // output default: '{page}/{totalPages}' 
     52                        // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} 
     53                        output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}' 
     54 
     55                        // apply disabled classname to the pager arrows when the rows at either extreme is visible 
     56                        updateArrows: true, 
     57 
     58                        // starting page of the pager (zero based index) 
     59                        page: 0, 
     60 
     61                        // Number of visible rows 
     62                        size: 10, 
     63 
     64                        // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) 
     65                        savePages: true, 
     66 
     67                        // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty 
     68                        // table row set to a height to compensate; default is false 
     69                        fixedHeight: false, 
     70 
     71                        // count child rows towards the set page size? (set true if it is a visible table row within the pager) 
     72                        // if true, child row(s) may not appear to be attached to its parent row, may be split across pages or 
     73                        // may distort the table if rowspan or cellspans are included. 
     74                        countChildRows: false, 
     75 
     76                        // remove rows from the table to speed up the sort of large tables. 
     77                        // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. 
     78                        removeRows: false, // removing rows in larger tables speeds up the sort 
     79 
     80                        // css class names of pager arrows 
     81                        cssFirst: '.first', // go to first page arrow 
     82                        cssPrev: '.prev', // previous page arrow 
     83                        cssNext: '.next', // next page arrow 
     84                        cssLast: '.last', // go to last page arrow 
     85                        cssGoto: '.gotoPage', // go to page selector - select dropdown that sets the current page 
     86                        cssPageDisplay: '.pagedisplay', // location of where the "output" is displayed 
     87                        cssPageSize: '.pagesize', // page size selector - select dropdown that sets the "size" option 
     88                        cssErrorRow: 'tablesorter-errorRow', // error information row 
     89 
     90                        // class added to arrows when at the extremes (i.e. prev/first arrows are "disabled" when on the first page) 
     91                        cssDisabled: 'disabled', // Note there is no period "." in front of this class name 
     92 
     93                        // stuff not set by the user 
     94                        totalRows: 0, 
     95                        totalPages: 0, 
     96                        filteredRows: 0, 
     97                        filteredPages: 0, 
     98                        ajaxCounter: 0, 
     99                        currentFilters: [], 
     100                        startRow: 0, 
     101                        endRow: 0, 
     102                        $size: null, 
     103                        last: {} 
     104 
     105                }; 
     106 
     107                var $this = this, 
     108 
     109                // hide arrows at extremes 
     110                pagerArrows = function(p, disable) { 
     111                        var a = 'addClass', 
     112                        r = 'removeClass', 
     113                        d = p.cssDisabled, 
     114                        dis = !!disable, 
     115                        tp = Math.min( p.totalPages, p.filteredPages ); 
     116                        if ( p.updateArrows ) { 
     117                                p.$container.find(p.cssFirst + ',' + p.cssPrev)[ ( dis || p.page === 0 ) ? a : r ](d); 
     118                                p.$container.find(p.cssNext + ',' + p.cssLast)[ ( dis || p.page === tp - 1 || p.totalPages === 0 ) ? a : r ](d); 
     119                        } 
     120                }, 
     121 
     122                updatePageDisplay = function(table, p, flag) { 
     123                        var i, pg, s, out, 
     124                                c = table.config, 
     125                                f = c.$table.hasClass('hasFilters') && !p.ajaxUrl, 
     126                                t = (c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered') + ',' + c.selectorRemove + 
     127                                        (p.countChildRows ? '' : ',.' + c.cssChildRow), 
     128                                sz = p.size || 10; // don't allow dividing by zero 
     129                        p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method 
     130                        p.filteredRows = (f) ? c.$tbodies.eq(0).children('tr').not('.' + t ).length : p.totalRows; 
     131                        p.filteredPages = (f) ? Math.ceil( p.filteredRows / sz ) || 1 : p.totalPages; 
     132                        if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) { 
     133                                t = (p.size * p.page > p.filteredRows); 
     134                                p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1); 
     135                                p.page = (t) ? 0 : p.page; 
     136                                p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) ); 
     137                                out = p.$container.find(p.cssPageDisplay); 
     138                                // form the output string (can now get a new output string from the server) 
     139                                s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || p.output : p.output ) 
     140                                        // {page} = one-based index; {page+#} = zero based index +/- value 
     141                                        .replace(/\{page([\-+]\d+)?\}/gi, function(m,n){ 
     142                                                return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0; 
     143                                        }) 
     144                                        // {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object) 
     145                                        .replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){ 
     146                                                var str = m.replace(/[{}\s]/g,''), 
     147                                                        extra = str.split(':'), 
     148                                                        data = p.ajaxData, 
     149                                                        // return zero for default page/row numbers 
     150                                                        deflt = /(rows?|pages?)$/i.test(str) ? 0 : ''; 
     151                                                return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt; 
     152                                        }); 
     153                                if (out.length) { 
     154                                        out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s); 
     155                                        if ( p.$goto.length ) { 
     156                                                t = ''; 
     157                                                pg = Math.min( p.totalPages, p.filteredPages ); 
     158                                                for ( i = 1; i <= pg; i++ ) { 
     159                                                        t += '<option>' + i + '</option>'; 
     160                                                } 
     161                                                p.$goto.html(t).val( p.page + 1 ); 
     162                                        } 
     163                                } 
     164                        } 
     165                        pagerArrows(p); 
     166                        if (p.initialized && flag !== false) { 
     167                                c.$table.trigger('pagerComplete', p); 
     168                                // save pager info to storage 
     169                                if (p.savePages && ts.storage) { 
     170                                        ts.storage(table, 'tablesorter-pager', { 
     171                                                page : p.page, 
     172                                                size : p.size 
     173                                        }); 
     174                                } 
     175                        } 
     176                }, 
     177 
     178                fixHeight = function(table, p) { 
     179                        var d, h, 
     180                                c = table.config, 
     181                                $b = c.$tbodies.eq(0); 
     182                        if (p.fixedHeight) { 
     183                                $b.find('tr.pagerSavedHeightSpacer').remove(); 
     184                                h = $.data(table, 'pagerSavedHeight'); 
     185                                if (h) { 
     186                                        d = h - $b.height(); 
     187                                        if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) { 
     188                                                $b.append('<tr class="pagerSavedHeightSpacer ' + c.selectorRemove.replace(/(tr)?\./g,'') + '" style="height:' + d + 'px;"></tr>'); 
     189                                        } 
     190                                } 
     191                        } 
     192                }, 
     193 
     194                changeHeight = function(table, p) { 
     195                        var $b = table.config.$tbodies.eq(0); 
     196                        $b.find('tr.pagerSavedHeightSpacer').remove(); 
     197                        $.data(table, 'pagerSavedHeight', $b.height()); 
     198                        fixHeight(table, p); 
     199                        $.data(table, 'pagerLastSize', p.size); 
     200                }, 
     201 
     202                hideRows = function(table, p){ 
     203                        if (!p.ajaxUrl) { 
     204                                var i, 
     205                                c = table.config, 
     206                                rows = c.$tbodies.eq(0).children(), 
     207                                l = rows.length, 
     208                                s = ( p.page * p.size ), 
     209                                e =  s + p.size, 
     210                                f = c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered', 
     211                                j = 0; // size counter 
     212                                for ( i = 0; i < l; i++ ){ 
     213                                        if ( !rows[i].className.match(f) ) { 
     214                                                rows[i].style.display = ( j >= s && j < e ) ? '' : 'none'; 
     215                                                // don't count child rows 
     216                                                j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !p.countChildRows ? 0 : 1; 
     217                                        } 
     218                                } 
     219                        } 
     220                }, 
     221 
     222                hideRowsSetup = function(table, p){ 
     223                        p.size = parseInt( p.$size.val(), 10 ) || p.size; 
     224                        $.data(table, 'pagerLastSize', p.size); 
     225                        pagerArrows(p); 
     226                        if ( !p.removeRows ) { 
     227                                hideRows(table, p); 
     228                                $(table).bind('sortEnd.pager filterEnd.pager', function(){ 
     229                                        hideRows(table, p); 
     230                                }); 
     231                        } 
     232                }, 
     233 
     234                renderAjax = function(data, table, p, xhr, exception){ 
     235                        // process data 
     236                        if ( typeof(p.ajaxProcessing) === "function" ) { 
     237                                // ajaxProcessing result: [ total, rows, headers ] 
     238                                var i, j, hsh, $f, $sh, t, th, d, l, $err, rr_count, 
     239                                        c = table.config, 
     240                                        $t = c.$table, 
     241                                        tds = '', 
     242                                        result = p.ajaxProcessing(data, table) || [ 0, [] ], 
     243                                        hl = $t.find('thead th').length; 
     244 
     245                                $t.find('thead tr.' + p.cssErrorRow).remove(); // Clean up any previous error. 
     246 
     247                                if ( exception ) { 
     248                                        if (c.debug) { 
     249                                                ts.log('Ajax Error', xhr, exception); 
     250                                        } 
     251                                        $err = $('<tr class="' + p.cssErrorRow + '"><td style="text-align:center;" colspan="' + hl + '">' + ( 
     252                                                xhr.status === 0 ? 'Not connected, verify Network' : 
     253                                                xhr.status === 404 ? 'Requested page not found [404]' : 
     254                                                xhr.status === 500 ? 'Internal Server Error [500]' : 
     255                                                exception === 'parsererror' ? 'Requested JSON parse failed' : 
     256                                                exception === 'timeout' ? 'Time out error' : 
     257                                                exception === 'abort' ? 'Ajax Request aborted' : 
     258                                                'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']' ) + '</td></tr>') 
     259                                        .click(function(){ 
     260                                                $(this).remove(); 
     261                                        }) 
     262                                        // add error row to thead instead of tbody, or clicking on the header will result in a parser error 
     263                                        .appendTo( $t.find('thead:first') ); 
     264                                        c.$tbodies.eq(0).empty(); 
     265                                } else { 
     266                                        // process ajax object 
     267                                        if (!$.isArray(result)) { 
     268                                                p.ajaxData = result; 
     269                                                p.totalRows = result.total; 
     270                                                th = result.headers; 
     271                                                d = result.rows; 
     272                                        } else { 
     273                                                // allow [ total, rows, headers ]  or [ rows, total, headers ] 
     274                                                t = isNaN(result[0]) && !isNaN(result[1]); 
     275                                                //ensure a zero returned row count doesn't fail the logical || 
     276                                                rr_count = result[t ? 1 : 0]; 
     277                                                p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count; 
     278                                                d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data 
     279                                                th = result[2]; // headers 
     280                                        } 
     281                                        l = d.length; 
     282                                        if (d instanceof jQuery) { 
     283                                                // append jQuery object 
     284                                                c.$tbodies.eq(0).empty().append(d); 
     285                                        } else if (l) { 
     286                                                // build table from array 
     287                                                for ( i = 0; i < l; i++ ) { 
     288                                                        tds += '<tr>'; 
     289                                                        for ( j = 0; j < d[i].length; j++ ) { 
     290                                                                // build tbody cells; watch for data containing HTML markup - see #434 
     291                                                                tds += /^\s*<td/.test(d[i][j]) ? $.trim(d[i][j]) : '<td>' + d[i][j] + '</td>'; 
     292                                                        } 
     293                                                        tds += '</tr>'; 
     294                                                } 
     295                                                // add rows to first tbody 
     296                                                p.processAjaxOnInit ? c.$tbodies.eq(0).html( tds ) : p.processAjaxOnInit = true; 
     297                                        } 
     298                                        // only add new header text if the length matches 
     299                                        if ( th && th.length === hl ) { 
     300                                                hsh = $t.hasClass('hasStickyHeaders'); 
     301                                                $sh = hsh ? c.widgetOptions.$sticky.children('thead:first').children().children() : ''; 
     302                                                $f = $t.find('tfoot tr:first').children(); 
     303                                                // don't change td headers (may contain pager) 
     304                                                c.$headers.filter('th').each(function(j){ 
     305                                                        var $t = $(this), icn; 
     306                                                        // add new test within the first span it finds, or just in the header 
     307                                                        if ( $t.find('.' + ts.css.icon).length ) { 
     308                                                                icn = $t.find('.' + ts.css.icon).clone(true); 
     309                                                                $t.find('.tablesorter-header-inner').html( th[j] ).append(icn); 
     310                                                                if ( hsh && $sh.length ) { 
     311                                                                        icn = $sh.eq(j).find('.' + ts.css.icon).clone(true); 
     312                                                                        $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icn); 
     313                                                                } 
     314                                                        } else { 
     315                                                                $t.find('.tablesorter-header-inner').html( th[j] ); 
     316                                                                if (hsh && $sh.length) { 
     317                                                                        $sh.eq(j).find('.tablesorter-header-inner').html( th[j] ); 
     318                                                                } 
     319                                                        } 
     320                                                        $f.eq(j).html( th[j] ); 
    26321                                                }); 
    27322                                        } 
    28                                         c.pagerPositionSet = true; 
    29                                 } 
    30                         } 
    31                          
    32                         function moveToFirstPage(table) { 
    33                                 var c = table.config; 
    34                                 c.page = 0; 
    35                                 moveToPage(table); 
    36                         } 
    37                          
    38                         function moveToLastPage(table) { 
    39                                 var c = table.config; 
    40                                 c.page = (c.totalPages-1); 
    41                                 moveToPage(table); 
    42                         } 
    43                          
    44                         function moveToNextPage(table) { 
    45                                 var c = table.config; 
    46                                 c.page++; 
    47                                 if(c.page >= (c.totalPages-1)) { 
    48                                         c.page = (c.totalPages-1); 
    49                                 } 
    50                                 moveToPage(table); 
    51                         } 
    52                          
    53                         function moveToPrevPage(table) { 
    54                                 var c = table.config; 
    55                                 c.page--; 
    56                                 if(c.page <= 0) { 
    57                                         c.page = 0; 
    58                                 } 
    59                                 moveToPage(table); 
    60                         } 
    61                                                  
    62                          
    63                         function moveToPage(table) { 
    64                                 var c = table.config; 
    65                                 if(c.page < 0 || c.page > (c.totalPages-1)) { 
    66                                         c.page = 0; 
    67                                 } 
    68                                  
    69                                 renderTable(table,c.rowsCopy); 
    70                         } 
    71                          
    72                         function renderTable(table,rows) { 
    73                                  
    74                                 var c = table.config; 
    75                                 var l = rows.length; 
    76                                 var s = (c.page * c.size); 
    77                                 var e = (s + c.size); 
    78                                 if(e > rows.length ) { 
     323                                } 
     324                                if (c.showProcessing) { 
     325                                        ts.isProcessing(table); // remove loading icon 
     326                                } 
     327                                // make sure last pager settings are saved, prevents multiple server side calls with 
     328                                // the same parameters 
     329                                p.last.totalPages =  p.totalPages = Math.ceil( p.totalRows / ( p.size || 10 ) ); 
     330                                p.last.currentFilters = p.currentFilters; 
     331                                p.last.sortList = (c.sortList || []).join(','); 
     332                                updatePageDisplay(table, p); 
     333                                fixHeight(table, p); 
     334                                // apply widgets after table has rendered 
     335                                $t.trigger('applyWidgets'); 
     336                                $t.trigger('update', [false, function(){ 
     337                                        if (p.initialized) { 
     338                                                $t.trigger('updateComplete'); 
     339                                                $t.trigger('pagerChange', p); 
     340                                        } 
     341                                }]); 
     342                        } 
     343                        if (!p.initialized) { 
     344                                p.initialized = true; 
     345                                $(table).trigger('pagerInitialized', p); 
     346                        } 
     347                }, 
     348 
     349                getAjax = function(table, p){ 
     350                        var url = getAjaxUrl(table, p), 
     351                        $doc = $(document), 
     352                        counter, 
     353                        c = table.config; 
     354                        if ( url !== '' ) { 
     355                                if (c.showProcessing) { 
     356                                        ts.isProcessing(table, true); // show loading icon 
     357                                } 
     358                                $doc.bind('ajaxError.pager', function(e, xhr, settings, exception) { 
     359                                        renderAjax(null, table, p, xhr, exception); 
     360                                        $doc.unbind('ajaxError.pager'); 
     361                                }); 
     362 
     363                                counter = ++p.ajaxCounter; 
     364 
     365                                p.ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl 
     366                                p.ajaxObject.success = function(data) { 
     367                                        // Refuse to process old ajax commands that were overwritten by new ones - see #443 
     368                                        if (counter < p.ajaxCounter){ 
     369                                                return; 
     370                                        } 
     371                                        renderAjax(data, table, p); 
     372                                        $doc.unbind('ajaxError.pager'); 
     373                                        if (typeof p.oldAjaxSuccess === 'function') { 
     374                                                p.oldAjaxSuccess(data); 
     375                                        } 
     376                                }; 
     377                                if (c.debug) { 
     378                                        ts.log('ajax initialized', p.ajaxObject); 
     379                                } 
     380                                $.ajax(p.ajaxObject); 
     381                        } 
     382                }, 
     383 
     384                getAjaxUrl = function(table, p) { 
     385                        var c = table.config, 
     386                                url = (p.ajaxUrl) ? p.ajaxUrl 
     387                                // allow using "{page+1}" in the url string to switch to a non-zero based index 
     388                                .replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); }) 
     389                                .replace(/\{size\}/g, p.size) : '', 
     390                        sl = c.sortList, 
     391                        fl = p.currentFilters || $(table).data('lastSearch') || [], 
     392                        sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/), 
     393                        filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/), 
     394                        arry = []; 
     395                        if (sortCol) { 
     396                                sortCol = sortCol[1]; 
     397                                $.each(sl, function(i,v){ 
     398                                        arry.push(sortCol + '[' + v[0] + ']=' + v[1]); 
     399                                }); 
     400                                // if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col" 
     401                                url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol ); 
     402                                arry = []; 
     403                        } 
     404                        if (filterCol) { 
     405                                filterCol = filterCol[1]; 
     406                                $.each(fl, function(i,v){ 
     407                                        if (v) { 
     408                                                arry.push(filterCol + '[' + i + ']=' + encodeURIComponent(v)); 
     409                                        } 
     410                                }); 
     411                                // if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol" 
     412                                url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol ); 
     413                                p.currentFilters = fl; 
     414                        } 
     415                        if ( typeof(p.customAjaxUrl) === "function" ) { 
     416                                url = p.customAjaxUrl(table, url); 
     417                        } 
     418                        if (c.debug) { 
     419                                ts.log('Pager ajax url: ' + url); 
     420                        } 
     421                        return url; 
     422                }, 
     423 
     424                renderTable = function(table, rows, p) { 
     425                        var i, $tb, 
     426                                l = rows && rows.length || 0, // rows may be undefined 
     427                                s = ( p.page * p.size ), 
     428                                e = ( s + p.size ); 
     429                        if ( l < 1 ) { return; } // empty table, abort! 
     430                        if ( p.page >= p.totalPages ) { 
     431                                // lets not render the table more than once 
     432                                moveToLastPage(table, p); 
     433                        } 
     434                        p.isDisabled = false; // needed because sorting will change the page and re-enable the pager 
     435                        if (p.initialized) { $(table).trigger('pagerChange', p); } 
     436 
     437                        if ( !p.removeRows ) { 
     438                                hideRows(table, p); 
     439                        } else { 
     440                                if ( e > rows.length ) { 
    79441                                        e = rows.length; 
    80442                                } 
    81                                  
    82                                  
    83                                 var tableBody = $(table.tBodies[0]); 
    84                                  
    85                                 // clear the table body 
    86                                  
    87                                 $.tablesorter.clearTableBody(table); 
    88                                  
    89                                 for(var i = s; i < e; i++) { 
    90                                          
    91                                         //tableBody.append(rows[i]); 
    92                                          
    93                                         var o = rows[i]; 
    94                                         var l = o.length; 
    95                                         for(var j=0; j < l; j++) { 
    96                                                  
    97                                                 tableBody[0].appendChild(o[j]); 
    98  
    99                                         } 
    100                                 } 
    101                                  
    102                                 fixPosition(table,tableBody); 
    103                                  
    104                                 $(table).trigger("applyWidgets"); 
    105                                  
    106                                 if( c.page >= c.totalPages ) { 
    107                                 moveToLastPage(table); 
    108                                 } 
    109                                  
    110                                 updatePageDisplay(c); 
    111                         } 
    112                          
    113                         this.appender = function(table,rows) { 
    114                                  
    115                                 var c = table.config; 
    116                                  
     443                                ts.clearTableBody(table); 
     444                                $tb = ts.processTbody(table, table.config.$tbodies.eq(0), true); 
     445                                for ( i = s; i < e; i++ ) { 
     446                                        $tb.append(rows[i]); 
     447                                } 
     448                                ts.processTbody(table, $tb, false); 
     449                        } 
     450 
     451                        updatePageDisplay(table, p); 
     452                        if ( !p.isDisabled ) { fixHeight(table, p); } 
     453                        $(table).trigger('applyWidgets'); 
     454                }, 
     455 
     456                showAllRows = function(table, p){ 
     457                        if ( p.ajax ) { 
     458                                pagerArrows(p, true); 
     459                        } else { 
     460                                p.isDisabled = true; 
     461                                $.data(table, 'pagerLastPage', p.page); 
     462                                $.data(table, 'pagerLastSize', p.size); 
     463                                p.page = 0; 
     464                                p.size = p.totalRows; 
     465                                p.totalPages = 1; 
     466                                $(table).addClass('pagerDisabled').find('tr.pagerSavedHeightSpacer').remove(); 
     467                                renderTable(table, table.config.rowsCopy, p); 
     468                                if (table.config.debug) { 
     469                                        ts.log('pager disabled'); 
     470                                } 
     471                        } 
     472                        // disable size selector 
     473                        p.$size.add(p.$goto).each(function(){ 
     474                                $(this).addClass(p.cssDisabled)[0].disabled = true; 
     475                        }); 
     476                }, 
     477 
     478                moveToPage = function(table, p, flag) { 
     479                        if ( p.isDisabled ) { return; } 
     480                        var c = table.config, 
     481                                l = p.last, 
     482                                pg = Math.min( p.totalPages, p.filteredPages ); 
     483                        if ( p.page < 0 ) { p.page = 0; } 
     484                        if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; } 
     485                        // don't allow rendering multiple times on the same page/size/totalpages/filters/sorts 
     486                        if ( l.page === p.page && l.size === p.size && l.totalPages === p.totalPages && 
     487                                (l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') && 
     488                                l.sortList === (c.sortList || []).join(',') ) { return; } 
     489                        if (c.debug) { 
     490                                ts.log('Pager changing to page ' + p.page); 
     491                        } 
     492                        p.last = { 
     493                                page : p.page, 
     494                                size : p.size, 
     495                                // fixes #408; modify sortList otherwise it auto-updates 
     496                                sortList : (c.sortList || []).join(','), 
     497                                totalPages : p.totalPages, 
     498                                currentFilters : p.currentFilters || [] 
     499                        }; 
     500                        if (p.ajax) { 
     501                                getAjax(table, p); 
     502                        } else if (!p.ajax) { 
     503                                renderTable(table, table.config.rowsCopy, p); 
     504                        } 
     505                        $.data(table, 'pagerLastPage', p.page); 
     506                        if (p.initialized && flag !== false) { 
     507                                c.$table.trigger('pageMoved', p); 
     508                                c.$table.trigger('applyWidgets'); 
     509                        } 
     510                }, 
     511 
     512                setPageSize = function(table, size, p) { 
     513                        p.size = size || p.size || 10; 
     514                        p.$size.val(p.size); 
     515                        $.data(table, 'pagerLastPage', p.page); 
     516                        $.data(table, 'pagerLastSize', p.size); 
     517                        p.totalPages = Math.ceil( p.totalRows / p.size ); 
     518                        moveToPage(table, p); 
     519                }, 
     520 
     521                moveToFirstPage = function(table, p) { 
     522                        p.page = 0; 
     523                        moveToPage(table, p); 
     524                }, 
     525 
     526                moveToLastPage = function(table, p) { 
     527                        p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); 
     528                        moveToPage(table, p); 
     529                }, 
     530 
     531                moveToNextPage = function(table, p) { 
     532                        p.page++; 
     533                        if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) { 
     534                                p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 ); 
     535                        } 
     536                        moveToPage(table, p); 
     537                }, 
     538 
     539                moveToPrevPage = function(table, p) { 
     540                        p.page--; 
     541                        if ( p.page <= 0 ) { 
     542                                p.page = 0; 
     543                        } 
     544                        moveToPage(table, p); 
     545                }, 
     546 
     547                destroyPager = function(table, p){ 
     548                        showAllRows(table, p); 
     549                        p.$container.hide(); // hide pager 
     550                        table.config.appender = null; // remove pager appender function 
     551                        p.initialized = false; 
     552                        $(table).unbind('destroy.pager sortEnd.pager filterEnd.pager enable.pager disable.pager'); 
     553                        if (ts.storage) { 
     554                                ts.storage(table, 'tablesorter-pager', ''); 
     555                        } 
     556                }, 
     557 
     558                enablePager = function(table, p, triggered){ 
     559                        var pg = p.$size.removeClass(p.cssDisabled).removeAttr('disabled'); 
     560                        p.$goto.removeClass(p.cssDisabled).removeAttr('disabled'); 
     561                        p.isDisabled = false; 
     562                        p.page = $.data(table, 'pagerLastPage') || p.page || 0; 
     563                        p.size = $.data(table, 'pagerLastSize') || parseInt(pg.find('option[selected]').val(), 10) || p.size || 10; 
     564                        pg.val(p.size); // set page size 
     565                        p.totalPages = Math.ceil( Math.min( p.totalPages, p.filteredPages ) / p.size ); 
     566                        if ( triggered ) { 
     567                                $(table).trigger('update'); 
     568                                setPageSize(table, p.size, p); 
     569                                hideRowsSetup(table, p); 
     570                                fixHeight(table, p); 
     571                                if (table.config.debug) { 
     572                                        ts.log('pager enabled'); 
     573                                } 
     574                        } 
     575                }; 
     576 
     577                $this.appender = function(table, rows) { 
     578                        var c = table.config, 
     579                                p = c.pager; 
     580                        if ( !p.ajax ) { 
    117581                                c.rowsCopy = rows; 
    118                                 c.totalRows = rows.length; 
    119                                 c.totalPages = Math.ceil(c.totalRows / c.size); 
    120                                  
    121                                 renderTable(table,rows); 
    122                         }; 
    123                          
    124                         this.defaults = { 
    125                                 size: 10, 
    126                                 offset: 0, 
    127                                 page: 0, 
    128                                 totalRows: 0, 
    129                                 totalPages: 0, 
    130                                 container: null, 
    131                                 cssNext: '.next', 
    132                                 cssPrev: '.prev', 
    133                                 cssFirst: '.first', 
    134                                 cssLast: '.last', 
    135                                 cssPageDisplay: '.pagedisplay', 
    136                                 cssPageSize: '.pagesize', 
    137                                 seperator: "/", 
    138                                 positionFixed: true, 
    139                                 appender: this.appender 
    140                         }; 
    141                          
    142                         this.construct = function(settings) { 
    143                                  
    144                                 return this.each(function() {    
    145                                          
    146                                         config = $.extend(this.config, $.tablesorterPager.defaults, settings); 
    147                                          
    148                                         var table = this, pager = config.container; 
    149                                  
    150                                         $(this).trigger("appendCache"); 
    151                                          
    152                                         config.size = parseInt($(".pagesize",pager).val()); 
    153                                          
    154                                         $(config.cssFirst,pager).click(function() { 
    155                                                 moveToFirstPage(table); 
     582                                p.totalRows = p.countChildRows ? c.$tbodies.eq(0).children().length : rows.length; 
     583                                p.size = $.data(table, 'pagerLastSize') || p.size || 10; 
     584                                p.totalPages = Math.ceil( p.totalRows / p.size ); 
     585                                renderTable(table, rows, p); 
     586                        } 
     587                }; 
     588 
     589                $this.construct = function(settings) { 
     590                        return this.each(function() { 
     591                                // check if tablesorter has initialized 
     592                                if (!(this.config && this.hasInitialized)) { return; } 
     593                                var t, ctrls, fxn, 
     594                                        table = this, 
     595                                        c = table.config, 
     596                                        p = c.pager = $.extend( {}, $.tablesorterPager.defaults, settings ), 
     597                                        $t = c.$table, 
     598                                        // added in case the pager is reinitialized after being destroyed. 
     599                                        pager = p.$container = $(p.container).addClass('tablesorter-pager').show(); 
     600                                if (c.debug) { 
     601                                        ts.log('Pager initializing'); 
     602                                } 
     603                                p.oldAjaxSuccess = p.oldAjaxSuccess || p.ajaxObject.success; 
     604                                c.appender = $this.appender; 
     605                                if (ts.filter && $.inArray('filter', c.widgets) >= 0) { 
     606                                        // get any default filter settings (data-value attribute) fixes #388 
     607                                        p.currentFilters = c.$table.data('lastSearch') || ts.filter.setDefaults(table, c, c.widgetOptions) || []; 
     608                                        // set, but don't apply current filters 
     609                                        ts.setFilters(table, p.currentFilters, false); 
     610                                } 
     611                                if (p.savePages && ts.storage) { 
     612                                        t = ts.storage(table, 'tablesorter-pager') || {}; // fixes #387 
     613                                        p.page = isNaN(t.page) ? p.page : t.page; 
     614                                        p.size = ( isNaN(t.size) ? p.size : t.size ) || 10; 
     615                                        $.data(table, 'pagerLastSize', p.size); 
     616                                } 
     617 
     618                                $t 
     619                                        .unbind('filterStart filterEnd sortEnd disable enable destroy update updateRows updateAll addRows pageSize '.split(' ').join('.pager ')) 
     620                                        .bind('filterStart.pager', function(e, filters) { 
     621                                                p.currentFilters = filters; 
     622                                                p.page = 0; // fixes #456 
     623                                        }) 
     624                                        // update pager after filter widget completes 
     625                                        .bind('filterEnd.pager sortEnd.pager', function() { 
     626                                                if (p.initialized) { 
     627                                                        moveToPage(table, p, false); 
     628                                                        updatePageDisplay(table, p, false); 
     629                                                        fixHeight(table, p); 
     630                                                } 
     631                                        }) 
     632                                        .bind('disable.pager', function(e){ 
     633                                                e.stopPropagation(); 
     634                                                showAllRows(table, p); 
     635                                        }) 
     636                                        .bind('enable.pager', function(e){ 
     637                                                e.stopPropagation(); 
     638                                                enablePager(table, p, true); 
     639                                        }) 
     640                                        .bind('destroy.pager', function(e){ 
     641                                                e.stopPropagation(); 
     642                                                destroyPager(table, p); 
     643                                        }) 
     644                                        .bind('update updateRows updateAll addRows '.split(' ').join('.pager '), function(e){ 
     645                                                e.stopPropagation(); 
     646                                                hideRows(table, p); 
     647                                        }) 
     648                                        .bind('pageSize.pager', function(e,v){ 
     649                                                e.stopPropagation(); 
     650                                                setPageSize(table, parseInt(v, 10) || 10, p); 
     651                                                hideRows(table, p); 
     652                                                updatePageDisplay(table, p, false); 
     653                                                if (p.$size.length) { p.$size.val(p.size); } // twice? 
     654                                        }) 
     655                                        .bind('pageSet.pager', function(e,v){ 
     656                                                e.stopPropagation(); 
     657                                                p.page = (parseInt(v, 10) || 1) - 1; 
     658                                                if (p.$goto.length) { p.$goto.val(p.size); } // twice? 
     659                                                moveToPage(table, p); 
     660                                                updatePageDisplay(table, p, false); 
     661                                        }); 
     662 
     663                                // clicked controls 
     664                                ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast ]; 
     665                                fxn = [ moveToFirstPage, moveToPrevPage, moveToNextPage, moveToLastPage ]; 
     666                                pager.find(ctrls.join(',')) 
     667                                        .unbind('click.pager') 
     668                                        .bind('click.pager', function(e){ 
     669                                                e.stopPropagation(); 
     670                                                var i, $t = $(this), l = ctrls.length; 
     671                                                if ( !$t.hasClass(p.cssDisabled) ) { 
     672                                                        for (i = 0; i < l; i++) { 
     673                                                                if ($t.is(ctrls[i])) { 
     674                                                                        fxn[i](table, p); 
     675                                                                        break; 
     676                                                                } 
     677                                                        } 
     678                                                } 
     679                                        }); 
     680 
     681                                // goto selector 
     682                                p.$goto = pager.find(p.cssGoto); 
     683                                if ( p.$goto.length ) { 
     684                                        p.$goto 
     685                                                .unbind('change') 
     686                                                .bind('change', function(){ 
     687                                                        p.page = $(this).val() - 1; 
     688                                                        moveToPage(table, p); 
     689                                                        updatePageDisplay(table, p, false); 
     690                                                }); 
     691                                } 
     692 
     693                                // page size selector 
     694                                p.$size = pager.find(p.cssPageSize); 
     695                                if ( p.$size.length ) { 
     696                                        p.$size.unbind('change.pager').bind('change.pager', function() { 
     697                                                p.$size.val( $(this).val() ); // in case there are more than one pagers 
     698                                                if ( !$(this).hasClass(p.cssDisabled) ) { 
     699                                                        setPageSize(table, parseInt( $(this).val(), 10 ), p); 
     700                                                        changeHeight(table, p); 
     701                                                } 
    156702                                                return false; 
    157703                                        }); 
    158                                         $(config.cssNext,pager).click(function() { 
    159                                                 moveToNextPage(table); 
    160                                                 return false; 
    161                                         }); 
    162                                         $(config.cssPrev,pager).click(function() { 
    163                                                 moveToPrevPage(table); 
    164                                                 return false; 
    165                                         }); 
    166                                         $(config.cssLast,pager).click(function() { 
    167                                                 moveToLastPage(table); 
    168                                                 return false; 
    169                                         }); 
    170                                         $(config.cssPageSize,pager).change(function() { 
    171                                                 setPageSize(table,parseInt($(this).val())); 
    172                                                 return false; 
    173                                         }); 
    174                                 }); 
    175                         }; 
    176                          
    177                 } 
    178         }); 
    179         // extend plugin scope 
    180         $.fn.extend({ 
    181         tablesorterPager: $.tablesorterPager.construct 
    182         }); 
    183          
    184 })(jQuery);                              
     704                                } 
     705 
     706                                // clear initialized flag 
     707                                p.initialized = false; 
     708                                // before initialization event 
     709                                $t.trigger('pagerBeforeInitialized', p); 
     710 
     711                                enablePager(table, p, false); 
     712 
     713                                if ( typeof(p.ajaxUrl) === 'string' ) { 
     714                                        // ajax pager; interact with database 
     715                                        p.ajax = true; 
     716                                        //When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side. 
     717                                        c.widgetOptions.filter_serversideFiltering = true; 
     718                                        c.serverSideSorting = true; 
     719                                        moveToPage(table, p); 
     720                                } else { 
     721                                        p.ajax = false; 
     722                                        // Regular pager; all rows stored in memory 
     723                                        $(this).trigger("appendCache", true); 
     724                                        hideRowsSetup(table, p); 
     725                                } 
     726 
     727                                changeHeight(table, p); 
     728 
     729                                // pager initialized 
     730                                if (!p.ajax) { 
     731                                        p.initialized = true; 
     732                                        $(table).trigger('pagerInitialized', p); 
     733                                } 
     734                        }); 
     735                }; 
     736 
     737        }() 
     738}); 
     739// extend plugin scope 
     740$.fn.extend({ 
     741        tablesorterPager: $.tablesorterPager.construct 
     742}); 
     743 
     744})(jQuery); 
  • extensions/UserAdvManager/trunk/admin/template/uam.css

    r18461 r26933  
    8585 
    8686/* jQuery tablesorter instructions */ 
    87 tr.throw 
     87tr.tablesorter-headerRow, throw 
    8888{ 
    8989cursor:pointer; 
     
    9191} 
    9292 
    93 th.header 
     93th.tablesorter-header 
    9494{ 
    9595background-image:url("./icon/bg.png"); 
     
    9999} 
    100100 
    101 th.headerSortDown 
     101th.tablesorter-headerDesc 
    102102{ 
    103103background-image:url("./icon/desc.png"); 
    104104} 
    105105 
    106 th.headerSortUp 
     106th.tablesorter-headerAsc 
    107107{ 
    108108background-image:url("./icon/asc.png"); 
     109} 
     110 
     111th.sorter-false { 
     112        background-image: none; 
    109113} 
    110114 
     
    116120  margin-bottom: -3px; 
    117121} 
     122 
     123table.table2 { 
     124        border: 1px solid #111; 
     125        margin: 1em auto; 
     126        padding: 0; 
     127  width: 97%; 
     128} 
  • extensions/UserAdvManager/trunk/admin/template/userlist.tpl

    r21747 r26933  
    22{combine_script id='jquery.cluetip' require='jquery' path='themes/default/js/plugins/jquery.cluetip.js'} 
    33{combine_script id='jquery.tablesorter' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.min.js'} 
    4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.js'} 
     4{combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.min.js'} 
    55 
    66{combine_css path= $UAM_PATH|@cat:'admin/template/uam.css'} 
     7 
    78 
    89<script type="text/javascript"> 
     
    2425          // pass the headers argument and assing a object  
    2526          headers: 
    26           {ldelim}  
    27               // assign the fourth column (we start counting zero)  
     27          {ldelim} 
     28              // assign the second column (we start counting zero)  
     29              1: 
     30              {ldelim}  
     31                  // disable it by setting the property sorter to false  
     32                  sorter: false 
     33              {rdelim}, 
     34              // assign the fifth column (we start counting zero)  
    2835              4: 
    2936              {ldelim}  
    3037                  // disable it by setting the property sorter to false  
    31                   sorter: false  
     38                  sorter: false 
    3239              {rdelim} 
    33           {rdelim}  
     40          {rdelim} 
    3441      {rdelim}) 
    3542      .tablesorterPager({ldelim}container: $("#pager"), positionFixed: false, size: 20, totalPages: 0{rdelim}); 
     
    4249</div> 
    4350 
    44 <form method="post" action="" class="general"> 
     51<form method="post" class="general"> 
    4552  <fieldset> 
    4653        <legend class="cluetip" title="{'UAM_Tracking registered users'|translate}|{'UAM_userlistTitle_d'|translate}">{'UAM_Tracking registered users'|@translate}</legend> 
    4754    {if count($users) > 0} 
    48       <table id="sorting" class="table2" width="97%" summary=""> 
     55      <table id="sorting" class="table2"> 
    4956                        <thead> 
    5057                        <tr class="throw"> 
  • extensions/UserAdvManager/trunk/admin/template/usermanager.tpl

    r21747 r26933  
    22{combine_script id='jquery.cluetip' require='jquery' path='themes/default/js/plugins/jquery.cluetip.js'} 
    33{combine_script id='jquery.tablesorter' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.min.js'} 
    4 {combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.js'} 
     4{combine_script id='jquery.tablesorter.pager' require='jquery' path=$UAM_PATH|@cat:'admin/template/js/jquery.tablesorter.pager.min.js'} 
    55 
    66{combine_css path= $UAM_PATH|@cat:'admin/template/uam.css'} 
     
    1616{rdelim}); 
    1717 
    18 $(document).ready(function()  
     18$(document).ready(function() 
    1919    {ldelim} 
    2020      $("#sorting") 
    21       .tablesorter({ldelim}sortList:[[6,1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim}{rdelim}{rdelim}) 
     21      .tablesorter({ldelim}sortList:[[6,1]], headers: {ldelim} 0: {ldelim} sorter: false {rdelim},2: {ldelim} sorter: false {rdelim}{rdelim}{rdelim}) 
    2222      .tablesorterPager({ldelim}container: $("#pager"), positionFixed: false, size: 20, totalPages: 0{rdelim}); 
    2323    {rdelim}  
     
    3333        <legend class="cluetip" title="{'UAM_Tracking confirmations'|translate}|{'UAM_usermanTitle_d'|translate}">{'UAM_Tracking confirmations'|@translate}</legend> 
    3434    {if count($users) > 0} 
    35       <table id="sorting" class="table2" width="97%" summary=""> 
     35      <table id="sorting" class="table2"> 
    3636                  <thead> 
    3737                        <tr class="throw"> 
Note: See TracChangeset for help on using the changeset viewer.