mirror of
https://github.com/Mottie/tablesorter.git
synced 2025-01-12 15:24:21 +00:00
Core & Filter: Add duplicateSpan option
Core: - Added `duplicateSpan` option (default is `true`). - Renamed `$.tablesorter.formatSortingOrder` to `$.tablesorter.getOrder`. - Include `table` in console.error if an issue is encountered during initialization. - Clean up warning when no parser is found for given data. - Fix `config.sortVars` js error for non-existent header cells. - Added unit tests. - Added "example-colspan.html" demo. Filter: - Filters that span multiple columns now have the correct data-column set. - Consolidated code that parsed data-column ranges into `findRange` function. - Added unit tests
This commit is contained in:
parent
36a8b5a28e
commit
60282f0787
183
docs/example-colspan.html
Normal file
183
docs/example-colspan.html
Normal file
@ -0,0 +1,183 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery plugin: Tablesorter 2.0 - Sorting & Filtering with Colspans</title>
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="js/jquery-latest.min.js"></script>
|
||||
|
||||
<!-- Demo stuff -->
|
||||
<link rel="stylesheet" href="css/jq.css">
|
||||
<link href="css/prettify.css" rel="stylesheet">
|
||||
<script src="js/prettify.js"></script>
|
||||
<script src="js/docs.js"></script>
|
||||
|
||||
<!-- Tablesorter: required -->
|
||||
<link rel="stylesheet" href="../css/theme.blue.css">
|
||||
<style id="css">.tablesorter-blue td[colspan] { color: red; } /* for demo purposes */</style>
|
||||
|
||||
<script src="../js/jquery.tablesorter.js"></script>
|
||||
<script src="../js/widgets/widget-filter.js"></script>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
var dupe = true;
|
||||
$( '#dupe' ).click( function() {
|
||||
dupe = !dupe;
|
||||
$( this ).text( '' + dupe );
|
||||
$( 'table' )[0].config.duplicateSpan = dupe;
|
||||
$( 'table' ).trigger( 'update' );
|
||||
});
|
||||
$('table').on('filterEnd', function( event, c ) {
|
||||
$( '#show-filter' ).html( '[ "' + c.lastSearch.join('", "') + '" ]' );
|
||||
});
|
||||
$('.search').click(function(){
|
||||
var $this = $(this),
|
||||
filter = [],
|
||||
col = $this.attr( 'data-column' );
|
||||
if ( col === 'all' ) {
|
||||
col = $('table')[0].config.columns;
|
||||
}
|
||||
filter[ col ] = $this.text();
|
||||
$.tablesorter.setFilters( $('table'), filter );
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id="js">$( function() {
|
||||
$( 'table' ).tablesorter({
|
||||
theme : 'blue',
|
||||
|
||||
duplicateSpan : true, // default setting
|
||||
|
||||
widthFixed: true,
|
||||
widgets : [ 'zebra', 'filter' ],
|
||||
widgetOptions : {
|
||||
filter_external: 'input.search',
|
||||
filter_reset: '.reset'
|
||||
}
|
||||
});
|
||||
|
||||
$('.sort').click(function() {
|
||||
// it is still possible to use 'a', 'd', 'n', 's' or 'o' on the second column
|
||||
// see http://mottie.github.io/tablesorter/docs/#sorton
|
||||
$('table').trigger('sorton', [ [[ $(this).text(), 'n' ]] ]);
|
||||
});
|
||||
|
||||
});</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="banner">
|
||||
<h1>table<em>sorter</em></h1>
|
||||
<h2>Sorting & Filtering with Colspans</h2>
|
||||
<h3>Flexible client-side table sorting</h3>
|
||||
<a href="index.html">Back to documentation</a>
|
||||
</div>
|
||||
<div id="main">
|
||||
|
||||
<p class="tip">
|
||||
<em>NOTE!</em>
|
||||
<ul>
|
||||
<li>Having a <code>colspan</code> in the tbody is not fully supported by all widgets, and there are still some minor issues to work out.</li>
|
||||
<li><span class="label alert">Alert</span> Cells with a <code>rowspan</code> are <em>not</em> currently supported.</li>
|
||||
<li><span class="label warning">Warning</span> Cells with a <code>colspan</code> will attempt to use the parser set for that column and <em>will not</em> use the parser for another column while sorting or filtering - try this <button class="search" data-column="3" type="button">>10</button> - the "17 Koala" cell is not parsed as a numeric value and is thus considered a string.</li>
|
||||
<li>The <code>duplicateSpan</code> option (storing of cache data) is a preliminary step in providing <code>colspan</code> support, it is by no means complete.</li>
|
||||
<li>This demo requires tablesorter v2.24.7+, as well the corresponding version of the filter widget.<br><br></li>
|
||||
|
||||
<li>Follow the demo steps to hopefully get the full understanding of how to use <code>colspan</code>s in the tbody.</li>
|
||||
<li>Ultimately, with the issues noted below, I would not recommend including an entire column in the tbody that does not have a corresponding header cell - <em>don't do what I did in this demo for the first two colums</em>.</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
<h1>Demo</h1>
|
||||
<div id="demo"><ul>
|
||||
<li>Sort Column <button class="sort" type="button">0</button> <button class="sort" type="button">1</button>
|
||||
(toggle sort direction) - There is no method to use the UI to sort the second column because it has no header; use "sorton" instead.
|
||||
</li>
|
||||
<li>Search:
|
||||
<button class="search" type="button" data-column="2">zyx</button>
|
||||
<button class="search" type="button" data-column="3">7</button>
|
||||
<button class="search" type="button" data-column="4">Koala</button>
|
||||
<button class="search" type="button" data-column="5">edu</button>,
|
||||
then toggle <code>duplicateSpan</code> : <button id="dupe" type="button">true</button>.
|
||||
</li>
|
||||
<li>Searching the first two columns <sup class="results xsmall">†</sup>:
|
||||
<ul>
|
||||
<li>Search using column <code>0</code> (zero):<br>
|
||||
<button class="search" type="button" data-column="0">4</button> (nothing visible in column filter)<br>
|
||||
<button class="search" type="button" data-column="1">>4</button> (search second column, nothing visible in filter)
|
||||
</li>
|
||||
<li>Search using column <code>6</code> (used by "all" filter):<br>
|
||||
<button class="search" type="button" data-column="6">4</button> (search both index columns)<sup class="results xsmall">‡</sup><br>
|
||||
<button class="search" type="button" data-column="6">1:4</button> (only search "Group" column)<br>
|
||||
<button class="search" type="button" data-column="6">2:>4</button> (search second column)
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Search:
|
||||
<input type="search" class="search" data-column="all" placeholder="Search all columns"><sup class="results xsmall">‡</sup>
|
||||
<button class="reset">Reset</button>
|
||||
<code id="show-filter"></code>
|
||||
|
||||
<p class="xsmall"><span class="results">†</span> The reason for this issue is that the filter input in the index column has this setting:
|
||||
<code>data-column="0-1"</code>, and it has not yet been worked out how to properly target that input.<br>
|
||||
<span class="results">‡</span> It is still being investigated as to why the search using the button targeting column 6 and the "all" input have different results (Enter "4" in the input and 4 rows will appear in the result, then click on the "4" to search both index columns - one less row).
|
||||
</p>
|
||||
|
||||
<table class="tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" colspan="2">Index (colspan 2)</th>
|
||||
<th colspan="4">Products</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Product ID</th>
|
||||
<th>Numeric</th>
|
||||
<th>Animals</th>
|
||||
<th >Url</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th colspan="2">Index</th>
|
||||
<th>Product ID</th>
|
||||
<th>Numeric</th>
|
||||
<th id="test">Animals</th>
|
||||
<th >Url</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr><td>Group 1</td><td style="width:100px">6</td><td>abc 9</td><td>155</td><td>Lion</td><td>http://www.nytimes.com/</td></tr>
|
||||
<tr><td>Group 4</td><td>1</td><td>abc 1</td><td>237</td><td colspan="2">Ox http://www.yahoo.com</td></tr>
|
||||
<tr><td>Group 1</td><td>2</td><td colspan="4">zyx 1 957 Koala http://www.mit.edu/</td></tr>
|
||||
<tr><td>Group 0</td><td>5</td><td>abc 2</td><td>56</td><td>Elephant</td><td>http://www.wikipedia.org/</td></tr>
|
||||
<tr><td>Group 3</td><td>0</td><td>abc 123</td><td colspan="2">17 Koala</td><td>http://www.google.com</td></tr>
|
||||
<tr><td>Group 2</td><td>8</td><td>zyx 9</td><td>10</td><td>Girafee</td><td>http://www.facebook.com</td></tr>
|
||||
<tr><td>Group 1</td><td>3</td><td colspan="2">zyx 4 767</td><td>Bison</td><td>http://www.whitehouse.gov/</td></tr>
|
||||
<tr><td>Group 2</td><td>4</td><td>abc 11</td><td>3</td><td>Chimp</td><td>http://www.ucla.edu/</td></tr>
|
||||
<tr><td>Group 4</td><td>7</td><td colspan="2">ABC 10 87</td><td>Zebra</td><td>http://www.google.com</td></tr>
|
||||
<tr><td>Group 3</td><td>9</td><td>zyx 12</td><td>0</td><td>Koala</td><td>http://www.nasa.gov/</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h1>Javascript</h1>
|
||||
<div id="javascript">
|
||||
<pre class="prettyprint lang-javascript"></pre>
|
||||
</div>
|
||||
<h1>CSS</h1>
|
||||
<div id="css">
|
||||
<pre class="prettyprint lang-css"></pre>
|
||||
</div>
|
||||
<h1>HTML</h1>
|
||||
<div id="html">
|
||||
<pre class="prettyprint lang-html"></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -340,11 +340,12 @@
|
||||
<li><a href="example-locale-sort.html">Sorting Accented Characters</a> (<a href="#sortlocalecompare"><code>sortLocaleCompare</code></a>; v2.24; <a href="https://github.com/Mottie/tablesorter/wiki/Language">languages</a>).</li>
|
||||
<li><a href="example-trigger-sort.html">Sort table using a link outside the table</a> (external link; <span class="updated version">v2.17.0</span>).</li>
|
||||
<li><a href="example-child-rows.html">Attach child rows (rows that sort with their parent row)</a> (<span class="updated version">v2.15.12</span>).</li>
|
||||
<li><a href="example-child-rows-filtered.html">Use child rows + filter widget</a> (<span class="updated version">v2.22.0</span>)</li>
|
||||
<li><a href="example-child-rows-filtered.html">Use child rows + filter widget</a> (<span class="updated version">v2.22.0</span>).</li>
|
||||
<li><a href="example-multiple-tbodies.html">Sorting with Multiple Tbodies</a> (v2.2).</li>
|
||||
<li><a href="example-header-column-span.html">Sorting Across Multiple Columns</a> (v2.3).</li>
|
||||
<li><a href="example-option-show-processing.html">Show a processing icon during sorting/filtering</a> (v2.4).</li>
|
||||
<li><a href="example-option-delay-init.html">Delay table initialization</a> (<a href="#delayinit"><code>delayInit</code></a>).</li>
|
||||
<li><a href="example-colspan.html">Sort & filter with colspans</a> (<a href="#duplicatecolspan"><code>duplicateSpan</code></a>; <span class="version">v2.24.7</span>).</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@ -462,9 +463,9 @@
|
||||
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.23.5</span>).</li>
|
||||
<li><a href="example-widget-filter-any-match.html">external option (match any column)</a> (<span class="version">v2.13.3</span>; <span class="version updated">v2.22.0</span>).</li>
|
||||
<li><a href="example-widget-filter-external-inputs.html">external inputs</a> (<span class="version">v2.14</span>; <span class="version updated">v2.18.0</span>).</li>
|
||||
<li><a href="example-widget-filter-custom.html">custom</a> (v2.3.6; <span class="version updated">v2.22.0</span>).</li>
|
||||
<li><a href="example-widget-filter-custom-search.html">custom searches</a> (<span class="version">v2.17.5</span>; <span class="version updated">v2.22.0</span>).</li>
|
||||
<li><a href="example-widget-filter-custom-search2.html">custom search (example #2)</a> (<span class="version">v2.19.1</span>; <span class="version updated">v2.24.6</span>).</li>
|
||||
<li><a href="example-widget-filter-custom.html">custom filter functions</a> (v2.3.6; <span class="version updated">v2.22.0</span>).</li>
|
||||
<li><a href="example-widget-filter-custom-search.html">custom search types</a> (<span class="version">v2.17.5</span>; <span class="version updated">v2.22.0</span>).</li>
|
||||
<li><a href="example-widget-filter-custom-search2.html">custom search type (example #2: date range)</a> (<span class="version">v2.19.1</span>; <span class="version updated">v2.24.6</span>).</li>
|
||||
<li><a href="example-widget-filter-childrows.html">child rows</a> (<span class="version">v2.23.4</span>).</li>
|
||||
<li>formatter: <a href="example-widget-filter-formatter-1.html">jQuery UI widgets</a> and <a href="example-widget-filter-formatter-2.html">HTML5 Elements</a> (v2.7.7; <span class="version updated">v2.17.5</span>).</li>
|
||||
<li>formatter: <a href="example-widget-filter-formatter-select2.html">select2</a> (<span class="version">v2.16.0</span>; <span class="version updated">v2.21.3</span>).</li>
|
||||
@ -583,6 +584,26 @@
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr id="duplicatespan">
|
||||
<td><a href="#" class="permalink">duplicateSpan</a></td>
|
||||
<td>Boolean</td>
|
||||
<td>true</td>
|
||||
<td>Any <code>colspan</code> cells in the tbody may have its content duplicated in the cache for each spanned column (<span class="version">v2.24.7</span>).
|
||||
<div class="collapsible">
|
||||
<p>If <code>true</code>, the cache will contain duplicated cell contents for every column the <code>colspan</code> includes. This makes it easier to sort & filter columns because a cell spanning all columns will only work with one parser. If <code>false</code>, the contents of cells that are spanned will be set to an empty string.</p>
|
||||
<pre class="prettyprint lang-js">// this row: <tr><td colspan="3">foo</td><td>bar</td></tr> results in this row cache:
|
||||
[ 'foo', 'foo', 'foo', 'bar' ] // if duplicateSpan = true
|
||||
[ 'foo', '', '', 'bar' ] // if duplicateSpan = false</pre>
|
||||
<span class="label warning">*NOTE*</span>
|
||||
<ul>
|
||||
<li>Cells in the tbody with a <code>rowspan</code> are <em>not yet supported</em> and will not sort or filter as you would expect.</li>
|
||||
<li>Having these values in the cache does not automatically guarantee that all widgets will work as expected with <code>colspan</code>s in the tbody (e.g. scroller widget with fixed columns)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
<td><a href="example-widget-filter.html">Example</a></td>
|
||||
</tr>
|
||||
|
||||
<tr id="cssasc">
|
||||
<td><a href="#" class="permalink">cssAsc</a></td>
|
||||
<td>String</td>
|
||||
|
@ -62,6 +62,7 @@
|
||||
|
||||
emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
|
||||
stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero
|
||||
duplicateSpan : true, // colspan cells in the tbody will have duplicated content in the cache for each spanned column
|
||||
textExtraction : 'basic', // text extraction method/function - function( node, table, cellIndex ){}
|
||||
textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function)
|
||||
textSorter : null, // choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
|
||||
@ -209,7 +210,7 @@
|
||||
if ( table.hasInitialized ) {
|
||||
console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
|
||||
} else {
|
||||
console.error( 'Stopping initialization! No table, thead or tbody' );
|
||||
console.error( 'Stopping initialization! No table, thead or tbody', table );
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -561,7 +562,7 @@
|
||||
// this may get updated numerous times if there are multiple rows
|
||||
c.sortVars[ column ] = {
|
||||
count : -1, // set to -1 because clicking on the header automatically adds one
|
||||
order: ts.formatSortingOrder( tmp ) ?
|
||||
order: ts.getOrder( tmp ) ?
|
||||
[ 1, 0, 2 ] : // desc, asc, unsorted
|
||||
[ 0, 1, 2 ], // asc, desc, unsorted
|
||||
lockedOrder : false
|
||||
@ -569,7 +570,7 @@
|
||||
tmp = ts.getData( $elem, configHeaders, 'lockedOrder' ) || false;
|
||||
if ( typeof tmp !== 'undefined' && tmp !== false ) {
|
||||
c.sortVars[ column ].lockedOrder = true;
|
||||
c.sortVars[ column ].order = ts.formatSortingOrder( tmp ) ? [ 1, 1, 1 ] : [ 0, 0, 0 ];
|
||||
c.sortVars[ column ].order = ts.getOrder( tmp ) ? [ 1, 1, 1 ] : [ 0, 0, 0 ];
|
||||
}
|
||||
// add cell to headerList
|
||||
c.headerList[ index ] = elem;
|
||||
@ -692,6 +693,12 @@
|
||||
if ( span > 0 ) {
|
||||
colIndex += span;
|
||||
max += span;
|
||||
while ( span + 1 > 0 ) {
|
||||
// set colspan columns to use the same parsers & extractors
|
||||
list.parsers[ colIndex - span ] = parser;
|
||||
list.extractors[ colIndex - span ] = extractor;
|
||||
span--;
|
||||
}
|
||||
}
|
||||
}
|
||||
colIndex++;
|
||||
@ -834,7 +841,7 @@
|
||||
buildCache : function( c, callback, $tbodies ) {
|
||||
var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,
|
||||
cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,
|
||||
colMax, span, cacheIndex, max, len,
|
||||
colMax, span, cacheIndex, hasParser, max, len, index,
|
||||
table = c.table,
|
||||
parsers = c.parsers;
|
||||
// update tbody variable
|
||||
@ -909,22 +916,31 @@
|
||||
max = c.columns;
|
||||
for ( colIndex = 0; colIndex < max; ++colIndex ) {
|
||||
cell = $row[ 0 ].cells[ colIndex ];
|
||||
if ( typeof parsers[ cacheIndex ] === 'undefined' ) {
|
||||
if ( c.debug ) {
|
||||
console.warn( 'No parser found for column ' + colIndex + '; cell:', cell, 'does it have a header?' );
|
||||
if ( cell && cacheIndex < c.columns ) {
|
||||
hasParser = typeof parsers[ cacheIndex ] !== 'undefined';
|
||||
if ( !hasParser && c.debug ) {
|
||||
console.warn( 'No parser found for row: ' + rowIndex + ', column: ' + colIndex +
|
||||
'; cell containing: "' + $(cell).text() + '"; does it have a header?' );
|
||||
}
|
||||
} else if ( cell ) {
|
||||
val = ts.getElementText( c, cell, cacheIndex );
|
||||
rowData.raw[ cacheIndex ] = val; // save original row text
|
||||
// save raw column text even if there is no parser set
|
||||
txt = ts.getParsedText( c, cell, cacheIndex, val );
|
||||
cols[ cacheIndex ] = txt;
|
||||
if ( ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
|
||||
if ( hasParser && ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
|
||||
// determine column max value (ignore sign)
|
||||
colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );
|
||||
}
|
||||
// allow colSpan in tbody
|
||||
span = cell.colSpan - 1;
|
||||
if ( span > 0 ) {
|
||||
index = 0;
|
||||
while ( index <= span ) {
|
||||
// duplicate text (or not) to spanned columns
|
||||
rowData.raw[ cacheIndex + index ] = c.duplicateSpan || index === 0 ? val : '';
|
||||
cols[ cacheIndex + index ] = c.duplicateSpan || index === 0 ? val : '';
|
||||
index++;
|
||||
}
|
||||
cacheIndex += span;
|
||||
max += span;
|
||||
}
|
||||
@ -953,7 +969,7 @@
|
||||
if ( !val[ 'row: ' + cacheIndex ] ) {
|
||||
val[ 'row: ' + cacheIndex ] = {};
|
||||
}
|
||||
val[ 'row: ' + cacheIndex ][ c.headerContent[ colIndex ] ] =
|
||||
val[ 'row: ' + cacheIndex ][ c.$headerIndexed[ colIndex ].text() ] =
|
||||
c.cache[ 0 ].normalized[ cacheIndex ][ colIndex ];
|
||||
}
|
||||
}
|
||||
@ -1054,7 +1070,7 @@
|
||||
col = parseInt( $el.attr( 'data-column' ), 10 ),
|
||||
end = col + c.$headers[ i ].colSpan;
|
||||
for ( ; col < end; col++ ) {
|
||||
include = include ? ts.isValueInArray( col, c.sortList ) > -1 : false;
|
||||
include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false;
|
||||
}
|
||||
return include;
|
||||
});
|
||||
@ -1159,6 +1175,14 @@
|
||||
col = parseInt( val[ 0 ], 10 );
|
||||
// prevents error if sorton array is wrong
|
||||
if ( col < c.columns ) {
|
||||
|
||||
// set order if not already defined - due to colspan header without associated header cell
|
||||
// adding this check prevents a javascript error
|
||||
if ( !c.sortVars[ col ].order ) {
|
||||
order = c.sortVars[ col ].order = ts.getOrder( c.sortInitialOrder ) ? [ 1, 0, 2 ] : [ 0, 1, 2 ];
|
||||
c.sortVars[ col ].count = 0;
|
||||
}
|
||||
|
||||
order = c.sortVars[ col ].order;
|
||||
dir = ( '' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );
|
||||
dir = dir ? dir[ 0 ] : '';
|
||||
@ -1437,6 +1461,7 @@
|
||||
ts.initSort( c, cell, event );
|
||||
}, 50 );
|
||||
}
|
||||
|
||||
var arry, indx, headerIndx, dir, temp, tmp, $header,
|
||||
notMultiSort = !event[ c.sortMultiSortKey ],
|
||||
table = c.table,
|
||||
@ -1708,7 +1733,7 @@
|
||||
return ( parsers && parsers[ column ] ) ? parsers[ column ].type || '' : '';
|
||||
},
|
||||
|
||||
formatSortingOrder : function( val ) {
|
||||
getOrder : function( val ) {
|
||||
// look for 'd' in 'desc' order; return true
|
||||
return ( /^d/i.test( val ) || val === 1 );
|
||||
},
|
||||
|
@ -208,7 +208,7 @@
|
||||
table = c.table,
|
||||
parsed = data.parsed[ data.index ],
|
||||
query = ts.formatFloat( data.iFilter.replace( tsfRegex.operators, '' ), table ),
|
||||
parser = c.parsers[ data.index ],
|
||||
parser = c.parsers[ data.index ] || {},
|
||||
savedSearch = query;
|
||||
// parse filter value in case we're comparing numbers ( dates )
|
||||
if ( parsed || parser.type === 'numeric' ) {
|
||||
@ -629,7 +629,7 @@
|
||||
for ( indx = 0; indx <= c.columns; indx++ ) {
|
||||
// include data-column='all' external filters
|
||||
col = indx === c.columns ? 'all' : indx;
|
||||
filters[indx] = $filters
|
||||
filters[ indx ] = $filters
|
||||
.filter( '[data-column="' + col + '"]' )
|
||||
.attr( wo.filter_defaultAttrib ) || filters[indx] || '';
|
||||
}
|
||||
@ -651,11 +651,12 @@
|
||||
buildFilter = '<tr role="row" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
|
||||
for ( column = 0; column < columns; column++ ) {
|
||||
if ( c.$headerIndexed[ column ].length ) {
|
||||
buildFilter += '<td data-column="' + column + '"';
|
||||
// account for entire column set with colspan. See #1047
|
||||
tmp = c.$headerIndexed[ column ] && c.$headerIndexed[ column ][0].colSpan || 0;
|
||||
if ( tmp > 1 ) {
|
||||
buildFilter += ' colspan="' + tmp + '"';
|
||||
buildFilter += '<td data-column="' + column + '-' + ( column + tmp - 1 ) + '" colspan="' + tmp + '"';
|
||||
} else {
|
||||
buildFilter += '<td data-column="' + column + '"';
|
||||
}
|
||||
if ( arry ) {
|
||||
buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
|
||||
@ -674,7 +675,8 @@
|
||||
// assuming last cell of a column is the main column
|
||||
$header = c.$headerIndexed[ column ];
|
||||
if ( $header && $header.length ) {
|
||||
$filter = c.$filters.filter( '[data-column="' + column + '"]' );
|
||||
// $filter = c.$filters.filter( '[data-column="' + column + '"]' );
|
||||
$filter = tsf.getColumnElm( c, c.$filters, column );
|
||||
ffxn = ts.getColumnData( table, wo.filter_functions, column );
|
||||
makeSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
|
||||
$header.hasClass( 'filter-select' );
|
||||
@ -714,7 +716,8 @@
|
||||
name = ( $.isArray( wo.filter_cssFilter ) ?
|
||||
( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
|
||||
wo.filter_cssFilter ) || '';
|
||||
buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', column );
|
||||
// copy data-column from table cell (it will include colspan)
|
||||
buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', $filter.attr( 'data-column' ) );
|
||||
if ( disabled ) {
|
||||
buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
|
||||
}
|
||||
@ -923,22 +926,18 @@
|
||||
}
|
||||
return $input || $();
|
||||
},
|
||||
multipleColumns: function( c, $input ) {
|
||||
findRange: function( c, val, ignoreRanges ) {
|
||||
// look for multiple columns '1-3,4-6,8' in data-column
|
||||
var temp, ranges, range, start, end, singles, i, indx, len,
|
||||
wo = c.widgetOptions,
|
||||
// only target 'all' column inputs on initialization
|
||||
// & don't target 'all' column inputs if they don't exist
|
||||
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
|
||||
columns = [],
|
||||
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
|
||||
if ( /^[0-9]+$/.test(val)) {
|
||||
return parseInt( val, 10 );
|
||||
columns = [];
|
||||
if ( /^[0-9]+$/.test( val ) ) {
|
||||
// always return an array
|
||||
return [ parseInt( val, 10 ) ];
|
||||
}
|
||||
// process column range
|
||||
if ( targets && /-/.test( val ) ) {
|
||||
if ( !ignoreRanges && /-/.test( val ) ) {
|
||||
ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
|
||||
len = ranges.length;
|
||||
len = ranges ? ranges.length : 0;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
range = ranges[indx].split( /\s*-\s*/ );
|
||||
start = parseInt( range[0], 10 ) || 0;
|
||||
@ -957,7 +956,7 @@
|
||||
}
|
||||
}
|
||||
// process single columns
|
||||
if ( targets && /,/.test( val ) ) {
|
||||
if ( !ignoreRanges && /,/.test( val ) ) {
|
||||
singles = val.split( /\s*,\s*/ );
|
||||
len = singles.length;
|
||||
for ( i = 0; i < len; i++ ) {
|
||||
@ -977,6 +976,23 @@
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
getColumnElm: function( c, $elements, column ) {
|
||||
// data-column may contain multiple columns '1-3,5-6,8'
|
||||
// replaces: c.$filters.filter( '[data-column="' + column + '"]' );
|
||||
return $elements.filter( function() {
|
||||
var cols = tsf.findRange( c, $( this ).attr( 'data-column' ) );
|
||||
return $.inArray( column, cols ) > -1;
|
||||
});
|
||||
},
|
||||
multipleColumns: function( c, $input ) {
|
||||
// look for multiple columns '1-3,4-6,8' in data-column
|
||||
var wo = c.widgetOptions,
|
||||
// only target 'all' column inputs on initialization
|
||||
// & don't target 'all' column inputs if they don't exist
|
||||
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
|
||||
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
|
||||
return tsf.findRange( c, val, !targets );
|
||||
},
|
||||
processTypes: function( c, data, vars ) {
|
||||
var ffxn,
|
||||
filterMatched = null,
|
||||
|
24
test.html
24
test.html
@ -127,6 +127,30 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table id="table6" class="tester">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" colspan="2">Index</th>
|
||||
<th colspan="4">Sort All Columns</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Product ID</th>
|
||||
<th>Numeric</th>
|
||||
<th id="test">Animals</th>
|
||||
<th >Url</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>G1</td><td>6</td><td>a9</td><td>155</td><td>L</td><td>nytimes</td></tr>
|
||||
<tr><td>G1</td><td>2</td><td colspan="4">z1 957 K mit</td></tr>
|
||||
<tr><td>G3</td><td>0</td><td>a13</td><td colspan="2">17 K</td><td>google</td></tr>
|
||||
<tr><td>G2</td><td>8</td><td>z9</td><td>10</td><td>G</td><td>facebook</td></tr>
|
||||
<tr><td>G1</td><td>3</td><td colspan="2">z24 67</td><td>B</td><td>whitehouse</td></tr>
|
||||
<tr><td>G4</td><td colspan="2">7 A10</td><td>87</td><td>Z</td><td>google</td></tr>
|
||||
<tr><td>G3</td><td>9</td><td>z12</td><td>0</td><td colspan="2">K nasa</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div id="testblock" class="tester"></div>
|
||||
<div id="testblock2" class="tester"></div>
|
||||
|
||||
|
@ -141,12 +141,29 @@ jQuery(function($){
|
||||
assert.cacheCompare( this.table, 3, [ 12, 18, 13, 18 ], 'starting filter value on age column', true );
|
||||
});
|
||||
|
||||
QUnit.test( 'Filter column range', function(assert) {
|
||||
expect(10);
|
||||
var range = $.tablesorter.filter.findRange,
|
||||
c = { columns: 10 }; // psuedo table.config
|
||||
|
||||
assert.deepEqual( range( c, '6' ), [ 6 ], '6' );
|
||||
assert.deepEqual( range( c, '5, 6' ), [ 5,6 ], '5, 6' );
|
||||
assert.deepEqual( range( c, '5 - 6' ), [ 5,6 ], '5 - 6' );
|
||||
assert.deepEqual( range( c, '1-3,5-6,8' ), [ 1,2,3,5,6,8 ], '1-3,5-6,8' );
|
||||
assert.deepEqual( range( c, '6- 3, 2,4' ), [ 3,4,5,6,2,4 ], '6- 3,2,4 (dupes included)' );
|
||||
assert.deepEqual( range( c, '-1-3, 11' ), [ 1,2,3 ], '-1-3, 11 (negative & out of range ignored)' );
|
||||
assert.deepEqual( range( c, '8-12' ), [ 8,9 ], '8-12 (not out of range)' );
|
||||
assert.deepEqual( range( c, 'all' ), [ 0,1,2,3,4,5,6,7,8,9 ], 'all' );
|
||||
assert.deepEqual( range( c, 'any-text' ), [ 0,1,2,3,4,5,6,7,8,9 ], 'text with dash -> all columns' );
|
||||
assert.deepEqual( range( c, 'a-b-c,100' ), [ 0,1,2,3,4,5,6,7,8,9 ], 'text with dashes & commas -> all columns' );
|
||||
});
|
||||
|
||||
QUnit.test( 'Filter searches', function(assert) {
|
||||
var ts = this.ts,
|
||||
c = this.c,
|
||||
wo = this.wo,
|
||||
$table = this.$table,
|
||||
table = this.table;
|
||||
c = this.c,
|
||||
wo = this.wo,
|
||||
$table = this.$table,
|
||||
table = this.table;
|
||||
expect(33);
|
||||
|
||||
return QUnit.SequentialRunner(
|
||||
|
@ -143,11 +143,13 @@ jQuery(function($){
|
||||
$table3 = $('#table3'),
|
||||
$table4 = $('#table4'),
|
||||
$table5 = $('#table5'), // empty table
|
||||
$table6 = $('#table6'), // colspan table
|
||||
table1 = $table1[0],
|
||||
table2 = $table2[0],
|
||||
table3 = $table3[0],
|
||||
table4 = $table4[0],
|
||||
table5 = $table5[0],
|
||||
table6 = $table6[0],
|
||||
th0 = $table1.find('th')[0], // first table header cell
|
||||
init = false,
|
||||
sortIndx = 0,
|
||||
@ -210,6 +212,7 @@ jQuery(function($){
|
||||
});
|
||||
|
||||
$table5.tablesorter();
|
||||
$table6.tablesorter();
|
||||
|
||||
QUnit.module('core');
|
||||
/************************************************
|
||||
@ -610,6 +613,42 @@ jQuery(function($){
|
||||
|
||||
});
|
||||
|
||||
|
||||
QUnit.test( 'colspan parsing', function(assert) {
|
||||
assert.expect(2);
|
||||
|
||||
t = [
|
||||
'g1', '6', 'a9', 155, 'l', 'nytimes',
|
||||
'g1', '2', 'z1 957 K mit', 'z1 957 K mit', 'z1 957 K mit', 'z1 957 K mit', // colspan 4
|
||||
'g3', '0', 'a13', '17 K', '17 K', 'google',
|
||||
'g2', '8', 'z9', 10, 'g', 'facebook',
|
||||
'g1', '3', 'z24 67', 'z24 67', 'b', 'whitehouse',
|
||||
'g4', '7 A10', '7 A10', 87, 'z', 'google',
|
||||
'g3', '9', 'z12', 0, 'K nasa', 'K nasa'
|
||||
];
|
||||
assert.cacheCompare( table6,'all', t, 'colspans in tbody (duplicateSpan:true)' );
|
||||
|
||||
$('#testblock').html('<table class="tablesorter">' +
|
||||
'<thead><tr><th>1</th><th>2</th><th>3</th><th>4</th></tr></thead>' +
|
||||
'<tbody>' +
|
||||
'<tr><td>1</td><td colspan="2">2</td><td>3</td></tr>' +
|
||||
'<tr><td colspan="3">y</td><td>z</td></tr>' +
|
||||
'<tr><td>a</td><td>b</td><td colspan="2">c</td></tr>' +
|
||||
'</tbody></table>')
|
||||
.find('table')
|
||||
.tablesorter({
|
||||
headers : { '*' : { sorter: 'text' } },
|
||||
duplicateSpan: false
|
||||
});
|
||||
t = [
|
||||
'1', '2', '', '3',
|
||||
'y', '', '', 'z',
|
||||
'a', 'b', 'c', ''
|
||||
];
|
||||
assert.cacheCompare( $('#testblock table')[0], 'all', t, 'colspans not duplicated in cache (duplicateSpan:false)' );
|
||||
|
||||
});
|
||||
|
||||
QUnit.test( 'sorton methods', function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user