Changeset 10161


Ignore:
Timestamp:
Apr 8, 2011, 1:30:56 PM (9 years ago)
Author:
datajulien
Message:

nbc_ThemeChanger_admin

Piwigo 2.2 compatibility upgrade

url rewrite for modification and suppression actions.

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

Modified files:

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

Location:
extensions/nbc_ThemeChanger
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • extensions/nbc_ThemeChanger/Version.txt

    r10134 r10161  
     1Version 2.2.0.b
     2[lang=fr]
     3Mise en compatibilité avec piwigo 2.2
     4        ré-écriture de l'url lors d'une modification ou d'une suppression d'associations
     5
     6Mise à jour de jquery.tablesorter en version 2.0.5b et correction d'un bug js quand le tableau est vide
     7
     8fichiers modifiés :
     9        main.inc.php
     10        admin/nbc_themeChanger_admin.tpl
     11        admin/nbc_themeChanger_admin.php
     12        include/jquery.tablesorter.js
     13[/lang=fr]
     14[lang=en]
     15Piwigo 2.2 compatibility upgrade
     16        url rewrite for modification and suppression actions.
     17
     18Update in version 2.0.5b of jquery.tablesorter plugin and correction of the autosort js bug when the table is empty
     19       
     20Modified files:
     21        main.inc.php
     22        admin/nbc_themeChanger_admin.tpl
     23        admin/nbc_themeChanger_admin.php
     24        include/jquery.tablesorter.js
     25[/lang=en]
     26
     27[lang=it]
     28Compatibilità con Piwigo 2.2
     29        riscrittura del URL per le azioni di modificazione e eliminazione
     30
     31aggiornamento della versione di jquery.tablesorter in 2.0.5b e correzione dell'anomalia sull'ordine quando la tabella è vuota
     32
     33File modificati:
     34        main.inc.php
     35        admin/nbc_themeChanger_admin.tpl
     36        admin/nbc_themeChanger_admin.php
     37        include/jquery.tablesorter.js
     38[/lang=it]
     39
     40--------------------------------------------------
    141Version 2.2.0.a
    242[lang=fr]
  • extensions/nbc_ThemeChanger/admin/nbc_ThemeChanger_admin.php

    r6648 r10161  
    1212$me = get_plugin_data($plugin_id);
    1313load_language('plugin.lang', NBC_ThemeChanger_PATH);
    14 $page_ThemeChanger_admin = get_admin_plugin_menu_link(__FILE__);
    15 
     14$page_ThemeChanger_admin = 'admin.php?page=plugin-'.basename(NBC_ThemeChanger_PATH);
     15
     16$my_base_url = $page_ThemeChanger_admin;
    1617
    1718//chargement des catégories
     
    2627  echo '0 '.$themes[1]['id'] .':'. $themes[1]['name'] .'<br>';
    2728  echo '0 '.$themes[2]['id'] .':'. $themes[2]['name'] .'<br>';
    28   echo '0 '.$themes[3]['id'] .':'. $themes[3]['name'] .'<br>';
    29   }
     29   }
    3030
    3131// Configuration du template
     
    3434    'U_HOME' => make_index_url(),
    3535        'F_ACTION' => add_url_params($page_ThemeChanger_admin, array()),
    36     'U_ADD_ASSOC' => add_url_params($page_ThemeChanger_admin, array('action' => 'add_assoc')),
    37     'U_HELP' => PHPWG_ROOT_PATH.'popuphelp.php?page=ThemeChanger',
     36    //'U_ADD_ASSOC' => add_url_params($page_ThemeChanger_admin, array('tab' => 'add_assoc')),
    3837        'Themes' => $themes,
    3938        'Categories' => $categories,
     
    5352// Mise a jour des paramètres du plugin
    5453if (isset($_POST['submit']) and !is_adviser())
    55         if ( (isset($_POST['categorychoise']) or isset($_POST['category_id'])) and isset($_POST['template']))
     54        if ( isset($_POST['categorychoise']) and isset($_POST['template']))
    5655        {       
    5756               
     
    6261                $theme = $_POST['template'];
    6362                $applysubcategory = isset($_POST['ApplySubCategories']) ? $_POST['ApplySubCategories'] : '';
    64                 $thecategory = isset($_POST['categorychoise']) ? $_POST['categorychoise'] : ( isset($_POST['category_id']) ? $_POST['category_id'] : '');
     63                $thecategory = isset($_POST['categorychoise']) ? $_POST['categorychoise'] : '';
    6564
    6665                $_POST['categorychoise'] = '';
    67                 $_POST['category_id'] = '';
    6866                $_POST['template'] = '';
    69                 $_GET['action'] = '';
     67                $_GET['tab'] = '';
    7068                $_POST['ApplySubCategories'] = '';
    7169
     
    131129        }
    132130
     131//DEBUG _GET   
     132else if ($__BEBUG)
     133{
     134        echo count($_GET).'<br/>';
     135        foreach ($_GET as $key => $value) {
     136                if ($key != "C") {
     137                        $querystring = $key."=".$value;
     138                        echo $querystring .'<br/>';
     139                }
     140        }
     141}
     142
    133143
    134144//delete an association
    135 if ( isset($_GET['action']) and ($_GET['action']=='del_assoc') and isset($_GET['id_cat']) and is_numeric($_GET['id_cat']) and !is_adviser() )
     145if ( isset($_GET['tab']) and ($_GET['tab']=='del_assoc') and isset($_GET['cat']) and is_numeric($_GET['cat']) and !is_adviser() )
    136146{
    137147
     
    142152    $element_ThemeChanger = explode("," , $Theme_Cat);
    143153
    144     if ($element_ThemeChanger[0] <> $_GET['id_cat'] and $element_ThemeChanger[0] <> '')
     154    if ($element_ThemeChanger[0] <> $_GET['cat'] and $element_ThemeChanger[0] <> '')
    145155    {
    146156      if ($newconf_nbc_ThemeChanger <> '')
     
    162172  array_push($page['infos'], l10n('nbc_ThemeChanger_save_config'));
    163173}
    164 
     174 
    165175//modify an association
    166 else if ( isset($_GET['action']) and ($_GET['action']=='mod_assoc') and isset($_GET['id_cat']) and is_numeric($_GET['id_cat']) and isset($_GET['id_theme']) )
     176else if ( isset($_GET['tab']) and ($_GET['tab']=='mod_assoc') and isset($_GET['cat']) and is_numeric($_GET['cat']) and isset($_GET['theme']) )
    167177{
    168178  $template->assign('formulaire',array(
    169         'DESCRIPION' => $lang['modify_assoc'].' : '.get_long_categorie_name($_GET['id_cat']),
    170         'THEMETOMODIFY' => $_GET['id_theme'],
    171         'NAMETOMODIFY' => get_long_categorie_name($_GET['id_cat']),
    172     'IDTOMODIFY' => $_GET['id_cat'],
     179        'DESCRIPION' => $lang['modify_assoc'].' : '.get_long_categorie_name($_GET['cat']),
     180        'THEMETOMODIFY' => $_GET['theme'],
     181        'NAMETOMODIFY' => get_long_categorie_name($_GET['cat']),
     182    'IDTOMODIFY' => $_GET['cat'],
    173183  ));
    174184}
    175185
    176186//add an association
    177 else if ( isset($_GET['action']) and ($_GET['action']=='add_assoc') )
     187else if ( isset($_GET['tab']) and ($_GET['tab']=='add_assoc') )
    178188{
    179189        $template->assign('formulaire', array(
     
    209219
    210220     array_push($assoc , array(
    211         //'CLASS' => ($num++ % 2 == 1) ? 'row2' : 'row1',
    212221        'CATEGORY_NAME' => get_cat_display_name_cache($row['uppercats'], null, false),
    213         'CATEGORY_ID'   => $element_ThemeChanger[0],
    214222        'TEMPLATE'              => $element_ThemeChanger[1],
    215223                'STATUS'                => my_get_pwg_theme_status($element_ThemeChanger[1]),
    216         'U_MODIFY'      => add_url_params($page_ThemeChanger_admin, array(
    217                         'action'                => 'mod_assoc',
    218                         'id_cat'                => $element_ThemeChanger[0],
    219                         'id_theme'              => $element_ThemeChanger[1],
    220         )),
    221         'U_DELETE'              => add_url_params($page_ThemeChanger_admin, array(
    222                         'action'                => 'del_assoc',
    223                         'id_cat'                => $element_ThemeChanger[0],
     224                'U_MODIFY'      => add_url_params($page_ThemeChanger_admin.'-mod_assoc', array(
     225                        'cat'           => $element_ThemeChanger[0],
     226                        'theme'         => $element_ThemeChanger[1],
     227                        )),
     228        'U_DELETE'              => add_url_params($page_ThemeChanger_admin.'-del_assoc', array(
     229                        'cat'           => $element_ThemeChanger[0],
    224230                )),
    225231        ));
  • extensions/nbc_ThemeChanger/admin/nbc_ThemeChanger_admin.tpl

    r10099 r10161  
    66jQuery(document).ready(function() {
    77   // call the tablesorter plugin
    8         jQuery("#tablesorter").tablesorter({
     8        jQuery("table#TCtablesorter").tablesorter({
    99                // extend the default setting to always sort on the first column
    1010                sortList : [[0,0]],
     
    4444        <h3>Theme Changer</h3>
    4545</div>
    46 <ul class="categoryActions">
    47         <!--li><a href="{$params.U_HELP}" onclick="popuphelp(this.href); return false;" title="{'HELP'|@translate}"><img src="{$themeconf.icon_dir}/help.png" class="button" alt="(?)"></a></li-->
    48 </ul>
    4946
    5047<!--br>
     
    5249<br-->
    5350
    54 <table class="table2" id="tablesorter">
     51<table class="table2" id="TCtablesorter">
    5552  <thead>
    5653  <tr class="throw">
     
    8683  </tr>
    8784  {/foreach}
    88  
     85  </tbody>
    8986  <!-- END assoc -->
    9087</table>
     
    9491  <fieldset>
    9592    <legend>{$formulaire.DESCRIPION}</legend>
    96     <table class="table2">
     93    <table class="table2" id="TCassoc">
     94                <thead>
    9795      <tr class="throw">
    9896        <th>{'Album'|@translate}</th>
     
    10098                <th>{'subAlbumsApply'|@translate}</th>
    10199      </tr>
     100          </thead>
     101          <tbody>
    102102      <tr>
    103103        <td>
     
    136136                </td>
    137137          </tr>
    138          
     138          </tbody>
    139139    </table>
    140        
    141140    <div align="center"><input class="submit" type="submit" value="{'submit'|@translate}" name="submit" {$TAG_INPUT_ENABLED} /></div>
    142 
    143141  </fieldset>
    144142</form>
  • extensions/nbc_ThemeChanger/include/jquery.tablesorter.js

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

    r10134 r10161  
    22/*
    33Plugin Name: NBC ThemeChanger
    4 Version: 2.2.0.A
     4Version: 2.2.0.B
    55Description: Permet d'associer à chaque catégorie virtuel ou physique un thème spécifique.
    66        ThemeChanger vous permet de spécifier pour chaque catérie un thème différent.
  • extensions/nbc_ThemeChanger/theme/style.css

    r6648 r10161  
    11/* tables */
    22
    3 table#tablesorter {
     3table#TCtablesorter {
    44        width: 80%;
    55}
    66
    7 table#tablesorter tbody .odd {
     7table#TCtablesorter tbody .odd {
    88        background-color:#ABBFFF;
    99}
    1010
    11 table#tablesorter thead tr .header {
     11table#TCtablesorter thead tr .header {
    1212        background-image: url(bg.gif);
    1313        background-repeat: no-repeat;
     
    1616}
    1717
    18 table#tablesorter thead tr .headerSortUp {
     18table#TCtablesorter thead tr .headerSortUp {
    1919        background-image: url(asc.gif);
    2020}
    21 table#tablesorter thead tr .headerSortDown {
     21table#TCtablesorter thead tr .headerSortDown {
    2222        background-image: url(desc.gif);
    2323}
Note: See TracChangeset for help on using the changeset viewer.