Merge "Support hash fragments in wfAppendQuery()"
[lhc/web/wiklou.git] / resources / src / jquery / jquery.tablesorter.js
index 69f8dd8..50bfa87 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*!
  * TableSorter for MediaWiki
  *
  * Written 2011 Leo Koppelkamm
  * and mw.language.months.
  *
  * Uses 'tableSorterCollation' in mw.config (if available)
- */
-/**
  *
- * @description Create a sortable table with multi-column sorting capabilities
+ * Create a sortable table with multi-column sorting capabilities
  *
- * @example $( 'table' ).tablesorter();
- * @desc Create a simple tablesorter interface.
+ *      // Create a simple tablesorter interface
+ *      $( 'table' ).tablesorter();
  *
- * @example $( 'table' ).tablesorter( { sortList: [ { 0: 'desc' }, { 1: 'asc' } ] } );
- * @desc Create a tablesorter interface initially sorting on the first and second column.
+ *      // Create a tablesorter interface, initially sorting on the first and second column
+ *      $( 'table' ).tablesorter( { sortList: [ { 0: 'desc' }, { 1: 'asc' } ] } );
  *
- * @option String cssHeader ( optional ) A string of the class name to be appended
- *         to sortable tr elements in the thead of the table. Default value:
- *         "header"
+ * @param {string} [cssHeader="header"] A string of the class name to be appended to sortable
+ *         tr elements in the thead of the table.
  *
- * @option String cssAsc ( optional ) A string of the class name to be appended to
- *         sortable tr elements in the thead on a ascending sort. Default value:
- *         "headerSortUp"
+ * @param {string} [cssAsc="headerSortUp"] A string of the class name to be appended to
+ *         sortable tr elements in the thead on a ascending sort.
  *
- * @option String cssDesc ( optional ) A string of the class name to be appended
- *         to sortable tr elements in the thead on a descending sort. Default
- *         value: "headerSortDown"
+ * @param {string} [cssDesc="headerSortDown"] A string of the class name to be appended to
+ *         sortable tr elements in the thead on a descending sort.
  *
- * @option String sortMultisortKey ( optional ) A string of the multi-column sort
- *         key. Default value: "shiftKey"
+ * @param {string} [sortMultisortKey="shiftKey"] A string of the multi-column sort key.
  *
- * @option Boolean cancelSelection ( optional ) Boolean flag indicating if
- *         tablesorter should cancel selection of the table headers text.
- *         Default value: true
+ * @param {boolean} [cancelSelection=true] Boolean flag indicating iftablesorter should cancel
+ *         selection of the table headers text.
  *
- * @option Array sortList ( optional ) An array containing objects specifying sorting.
- *         By passing more than one object, multi-sorting will be applied. Object structure:
+ * @param {Array} [sortList] An array containing objects specifying sorting. By passing more
+ *         than one object, multi-sorting will be applied. Object structure:
  *         { <Integer column index>: <String 'asc' or 'desc'> }
- *         Default value: []
  *
  * @event sortEnd.tablesorter: Triggered as soon as any sorting has been applied.
  *
- * @type jQuery
- *
- * @name tablesorter
- *
- * @cat Plugins/Tablesorter
- *
  * @author Christian Bach/christian.bach@polyester.se
  */
-
 ( function ( $, mw ) {
-       /* Local scope */
-
        var ts,
                parsers = [];
 
        /* Parser utility functions */
 
        function getParserById( name ) {
-               var i,
-                       len = parsers.length;
-               for ( i = 0; i < len; i++ ) {
+               var i;
+               for ( i = 0; i < parsers.length; i++ ) {
                        if ( parsers[ i ].id.toLowerCase() === name.toLowerCase() ) {
                                return parsers[ i ];
                        }
                        // Cast any numbers or other stuff to a string, methods
                        // like charAt, toLowerCase and split are expected.
                        return String( data );
-               } else {
-                       if ( !node ) {
-                               return $node.text();
-                       } else if ( node.tagName.toLowerCase() === 'img' ) {
-                               return $node.attr( 'alt' ) || ''; // handle undefined alt
-                       } else {
-                               return $.map( $.makeArray( node.childNodes ), function ( elem ) {
-                                       if ( elem.nodeType === Node.ELEMENT_NODE ) {
-                                               return getElementSortKey( elem );
-                                       } else {
-                                               return $.text( elem );
-                                       }
-                               } ).join( '' );
-                       }
                }
+               if ( !node ) {
+                       return $node.text();
+               }
+               if ( node.tagName.toLowerCase() === 'img' ) {
+                       return $node.attr( 'alt' ) || ''; // handle undefined alt
+               }
+               return $.map( $.makeArray( node.childNodes ), function ( elem ) {
+                       if ( elem.nodeType === Node.ELEMENT_NODE ) {
+                               return getElementSortKey( elem );
+                       }
+                       return $.text( elem );
+               } ).join( '' );
        }
 
        function detectParserForColumn( table, rows, column ) {
                var l = parsers.length,
+                       config = $( table ).data( 'tablesorter' ).config,
                        cellIndex,
                        nodeValue,
                        // Start with 1 because 0 is the fallback parser
                        needed = ( rows.length > 4 ) ? 5 : rows.length;
 
                while ( i < l ) {
-                       if ( rows[ rowIndex ] ) {
+                       // if this is a child row, continue to the next row (as buildCache())
+                       if ( rows[ rowIndex ] && !$( rows[ rowIndex ] ).hasClass( config.cssChildRow ) ) {
                                if ( rowIndex !== lastRowIndex ) {
                                        lastRowIndex = rowIndex;
                                        cellIndex = $( rows[ rowIndex ] ).data( 'columnToCell' )[ column ];
                        pos = normalized[ i ][ checkCell ];
 
                        l = row[ pos ].length;
-
                        for ( j = 0; j < l; j++ ) {
                                fragment.appendChild( row[ pos ][ j ] );
                        }
 
        function uniqueElements( array ) {
                var uniques = [];
-               $.each( array, function ( index, elem ) {
+               $.each( array, function ( i, elem ) {
                        if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
                                uniques.push( elem );
                        }
                        exploded,
                        $tableHeaders = $( [] ),
                        $tableRows = $( 'thead:eq(0) > tr', table );
+
                if ( $tableRows.length <= 1 ) {
                        $tableHeaders = $tableRows.children( 'th' );
                } else {
        }
 
        function isValueInArray( v, a ) {
-               var i,
-                               len = a.length;
-               for ( i = 0; i < len; i++ ) {
+               var i;
+               for ( i = 0; i < a.length; i++ ) {
                        if ( a[ i ][ 0 ] === v ) {
                                return true;
                        }
                $headers.removeClass( css[ 0 ] ).removeClass( css[ 1 ] ).attr( 'title', msg[ 1 ] );
 
                for ( var i = 0; i < list.length; i++ ) {
-                       $headers.eq( columnToHeader[ list[ i ][ 0 ] ] )
+                       $headers
+                               .eq( columnToHeader[ list[ i ][ 0 ] ] )
                                .addClass( css[ list[ i ][ 1 ] ] )
                                .attr( 'title', msg[ list[ i ][ 1 ] ] );
                }
 
        function multisort( table, sortList, cache ) {
                var i,
-                       sortFn = [],
-                       len = sortList.length;
-               for ( i = 0; i < len; i++ ) {
+                       sortFn = [];
+
+               for ( i = 0; i < sortList.length; i++ ) {
                        sortFn[ i ] = ( sortList[ i ][ 1 ] ) ? sortTextDesc : sortText;
                }
                cache.normalized.sort( function ( array1, array2 ) {
                        var i, col, ret;
-                       for ( i = 0; i < len; i++ ) {
+                       for ( i = 0; i < sortList.length; i++ ) {
                                col = sortList[ i ][ 0 ];
                                ret = sortFn[ i ].call( this, array1[ col ], array2[ col ] );
                                if ( ret !== 0 ) {
                        ascii = separatorTransformTable[ 0 ].split( '\t' ).concat( digitTransformTable[ 0 ].split( '\t' ) );
                        localised = separatorTransformTable[ 1 ].split( '\t' ).concat( digitTransformTable[ 1 ].split( '\t' ) );
 
-                       // Construct regex for number identification
+                       // Construct regexes for number identification
                        for ( i = 0; i < ascii.length; i++ ) {
                                ts.transformTable[ localised[ i ] ] = ascii[ i ];
                                digits.push( mw.RegExp.escape( localised[ i ] ) );
                $table.find( '> tbody > tr' ).each( function () {
                        var i,
                                col = 0,
-                               l = this.cells.length;
-                       for ( i = 0; i < l; i++ ) {
+                               len = this.cells.length;
+                       for ( i = 0; i < len; i++ ) {
                                $( this.cells[ i ] ).data( 'tablesorter', {
                                        realCellIndex: col,
                                        realRowIndex: this.rowIndex
         * Converts sort objects [ { Integer: String }, ... ] to the internally used nested array
         * structure [ [ Integer , Integer ], ... ]
         *
-        * @param sortObjects {Array} List of sort objects.
+        * @param {Array} sortObjects List of sort objects.
         * @return {Array} List of internal sort definitions.
         */
-
        function convertSortList( sortObjects ) {
                var sortList = [];
                $.each( sortObjects, function ( i, sortObject ) {
                                        $.data( table, 'tablesorter', { config: config } );
 
                                        // Get the CSS class names, could be done elsewhere
-                                       sortCSS = [ config.cssDesc, config.cssAsc ];
+                                       sortCSS = [ config.cssAsc, config.cssDesc ];
+                                       // Messages tell the the user what the *next* state will be
+                                       // so are in reverse order to the CSS classes.
                                        sortMsg = [ mw.msg( 'sort-descending' ), mw.msg( 'sort-ascending' ) ];
 
                                        // Build headers
                        },
 
                        addParser: function ( parser ) {
-                               var i,
-                                       len = parsers.length,
-                                       a = true;
-                               for ( i = 0; i < len; i++ ) {
-                                       if ( parsers[ i ].id.toLowerCase() === parser.id.toLowerCase() ) {
-                                               a = false;
-                                       }
-                               }
-                               if ( a ) {
+                               if ( !getParserById( parser.id ) ) {
                                        parsers.push( parser );
                                }
                        },
                format: function ( s ) {
                        var i, item,
                                a = s.split( '.' ),
-                               r = '',
-                               len = a.length;
-                       for ( i = 0; i < len; i++ ) {
+                               r = '';
+                       for ( i = 0; i < a.length; i++ ) {
                                item = a[ i ];
                                if ( item.length === 1 ) {
                                        r += '00' + item;
                        return ts.rgx.isoDate[ 0 ].test( s );
                },
                format: function ( s ) {
-                       var isodate,
-                               matches;
+                       var isodate, matches;
                        if ( !Date.prototype.toISOString ) {
                                // Old browsers don't understand iso, Fallback to US date parsing and ignore the time part.
                                matches = $.trim( s ).match( ts.rgx.isoDate[ 1 ] );
-                               if ( matches ) {
-                                       isodate = new Date( matches[ 2 ]  + '/' + matches[ 3 ] + '/' + matches[ 1 ] );
-                               } else {
+                               if ( !matches ) {
                                        return $.tablesorter.formatFloat( 0 );
                                }
+                               isodate = new Date( matches[ 2 ]  + '/' + matches[ 3 ] + '/' + matches[ 1 ] );
                        } else {
                                matches = s.match( ts.rgx.isoDate[ 0 ] );
-                               if ( matches ) {
-                                       isodate = new Date( $.trim( matches[ 0 ] ) );
-                               } else {
+                               if ( !matches ) {
                                        return $.tablesorter.formatFloat( 0 );
                                }
+                               isodate = new Date( $.trim( matches[ 0 ] ) );
                        }
                        return $.tablesorter.formatFloat( ( isodate !== undefined ) ? isodate.getTime() : 0 );
                },