mirror of
https://github.com/Mottie/tablesorter.git
synced 2024-11-15 23:54:22 +00:00
parent
65d48727ff
commit
9a67c022c4
2
dist/js/widgets/widget-filter.min.js
vendored
2
dist/js/widgets/widget-filter.min.js
vendored
File diff suppressed because one or more lines are too long
@ -16,15 +16,39 @@
|
||||
<!-- Tablesorter: required -->
|
||||
<link rel="stylesheet" href="../css/theme.blue.css">
|
||||
<script src="../js/jquery.tablesorter.js"></script>
|
||||
<script src="../js/jquery.tablesorter.widgets.js"></script>
|
||||
<!-- <script src="../js/jquery.tablesorter.widgets.js"></script> -->
|
||||
<script src="../js/widgets/widget-storage.js"></script>
|
||||
<script src="../js/widgets/widget-filter.js"></script>
|
||||
|
||||
<!-- Tablesorter: pager -->
|
||||
<link rel="stylesheet" href="../addons/pager/jquery.tablesorter.pager.css">
|
||||
<script src="../js/widgets/widget-pager.js"></script>
|
||||
|
||||
<style id="css">/* use class names to hide content for jQuery v3.0 - see https://github.com/jquery/jquery/issues/2308 */
|
||||
.hidden { display: none; }
|
||||
|
||||
/* override child row hovering defined in the theme file */
|
||||
#table2 tbody > tr.even.hover > td,
|
||||
#table2 tbody > tr.even:hover > td,
|
||||
#table2 tbody > tr.even:hover + tr.tablesorter-childRow > td,
|
||||
#table2 tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
|
||||
background-color: #fff;
|
||||
}
|
||||
#table2 tbody > tr.odd.hover > td,
|
||||
#table2 tbody > tr.odd:hover > td,
|
||||
#table2 tbody > tr.odd:hover + tr.tablesorter-childRow > td,
|
||||
#table2 tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
|
||||
background-color: #ebf2fa;
|
||||
}
|
||||
#table2 tbody > tr.even:hover > td,
|
||||
#table2 tbody > tr.odd:hover > td {
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script id="js">$( function() {
|
||||
|
||||
$(".tablesorter")
|
||||
var $table1 = $( '#table1' )
|
||||
.tablesorter({
|
||||
theme : 'blue',
|
||||
// this is the default setting
|
||||
@ -36,9 +60,9 @@
|
||||
widgetOptions: {
|
||||
// output default: '{page}/{totalPages}'
|
||||
// possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
|
||||
pager_output: '{startRow} - {endRow} / {filteredRows} ({totalRows})', // '{page}/{totalPages}'
|
||||
pager_removeRows: false,
|
||||
pager_output: '{startRow} - {endRow} / {filteredRows} ({totalRows})',
|
||||
|
||||
pager_removeRows: false,
|
||||
|
||||
// include child row content while filtering, if true
|
||||
filter_childRows : true,
|
||||
@ -52,29 +76,101 @@
|
||||
|
||||
});
|
||||
|
||||
// hide child rows
|
||||
$('.tablesorter-childRow td').hide();
|
||||
// hide child rows - get in the habit of not using .hide()
|
||||
// See http://jsfiddle.net/Mottie/u507846y/ & https://github.com/jquery/jquery/issues/1767
|
||||
// and https://github.com/jquery/jquery/issues/2308
|
||||
// This won't be a problem in jQuery v3.0+
|
||||
$table1.find( '.tablesorter-childRow td' ).addClass( 'hidden' );
|
||||
|
||||
// Toggle child row content (td), not hiding the row since we are using rowspan
|
||||
// Using delegate because the pager plugin rebuilds the table after each page change
|
||||
// "delegate" works in jQuery 1.4.2+; use "live" back to v1.3; for older jQuery - SOL
|
||||
$('.tablesorter').delegate('.toggle', 'click' ,function(){
|
||||
|
||||
$table1.delegate( '.toggle', 'click' ,function() {
|
||||
// use "nextUntil" to toggle multiple child rows
|
||||
// toggle table cells instead of the row
|
||||
$(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').toggle();
|
||||
|
||||
$( this )
|
||||
.closest( 'tr' )
|
||||
.nextUntil( 'tr.tablesorter-hasChildRow' )
|
||||
.find( 'td' )
|
||||
.toggleClass( 'hidden' );
|
||||
return false;
|
||||
});
|
||||
|
||||
// Toggle widgetFilterChildRows option
|
||||
$('button.toggle-option').click(function(){
|
||||
var c = $('.tablesorter')[0].config.widgetOptions,
|
||||
o = !c.filter_childRows;
|
||||
c.filter_childRows = o;
|
||||
$('.state').html(o.toString());
|
||||
// Toggle filter_childRows option
|
||||
$( 'button.toggle-combined' ).click( function() {
|
||||
var wo = $table1[0].config.widgetOptions,
|
||||
o = !wo.filter_childRows;
|
||||
wo.filter_childRows = o;
|
||||
$( '.state1' ).html( o.toString() );
|
||||
// update filter; include false parameter to force a new search
|
||||
$('table').trigger('search', false);
|
||||
$table1.trigger( 'search', false );
|
||||
return false;
|
||||
});
|
||||
|
||||
});</script>
|
||||
<script id="js2">$(function() {
|
||||
|
||||
var $table2 = $( '#table2' )
|
||||
.tablesorter({
|
||||
theme : 'blue',
|
||||
// this is the default setting
|
||||
cssChildRow : 'tablesorter-childRow',
|
||||
// initialize zebra and filter widgets
|
||||
widgets : [ 'zebra', 'filter' ],
|
||||
widgetOptions : {
|
||||
// include child row content while filtering, if true
|
||||
filter_childRows : true,
|
||||
// filter child row content by column; filter_childRows must also be true
|
||||
filter_childByColumn : true,
|
||||
// class name applied to filter row and each input
|
||||
filter_cssFilter : 'tablesorter-filter',
|
||||
// Set this option to false to make the searches case sensitive
|
||||
filter_ignoreCase : true,
|
||||
filter_reset: '.reset'
|
||||
}
|
||||
});
|
||||
|
||||
// hide child rows - don't use .hide() because filtered rows get a "filtered" class
|
||||
// added to them, and style="display: table-row;" will override this class
|
||||
// See http://jsfiddle.net/Mottie/u507846y/ & https://github.com/jquery/jquery/issues/1767
|
||||
// and https://github.com/jquery/jquery/issues/2308
|
||||
// This won't be a problem in jQuery v3.0+
|
||||
$table2.find( '.tablesorter-childRow' ).addClass( 'hidden' );
|
||||
|
||||
// Toggle child row content (td), not hiding the row since we are using rowspan
|
||||
// Using delegate because the pager plugin rebuilds the table after each page change
|
||||
// "delegate" works in jQuery 1.4.2+; use "live" back to v1.3; for older jQuery - SOL
|
||||
$table2.delegate( '.toggle', 'click' ,function() {
|
||||
// use "nextUntil" to toggle multiple child rows
|
||||
// toggle table cells instead of the row
|
||||
$( this )
|
||||
.closest( 'tr' )
|
||||
.nextUntil( 'tr.tablesorter-hasChildRow' )
|
||||
.toggleClass( 'hidden' );
|
||||
return false;
|
||||
});
|
||||
|
||||
// Toggle filter_childByColumn option
|
||||
$( 'button.toggle-byColumn' ).click(function(){
|
||||
var wo = $table2[0].config.widgetOptions,
|
||||
o = !wo.filter_childByColumn;
|
||||
wo.filter_childByColumn = o;
|
||||
$('.state2').html( o.toString() );
|
||||
// update filter; include false parameter to force a new search
|
||||
$table2.trigger('search', false);
|
||||
return false;
|
||||
});
|
||||
|
||||
// make demo search buttons work
|
||||
$( 'button[data-column]' ).on( 'click', function() {
|
||||
var $this = $( this ),
|
||||
totalColumns = $table2[0].config.columns,
|
||||
col = $this.data( 'column' ), // zero-based index or "all"
|
||||
filter = [];
|
||||
|
||||
// text to add to filter
|
||||
filter[ col === 'all' ? totalColumns : col ] = $this.text();
|
||||
$table2.trigger( 'search', [ filter ] );
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -91,32 +187,40 @@
|
||||
|
||||
<div id="main">
|
||||
|
||||
<p class="tip">
|
||||
<em>NOTE!</em>
|
||||
<div class="tip">
|
||||
<p><em>NOTE!</em></p>
|
||||
<ul>
|
||||
<li>Click the link in the Order # column to reveal the hidden child row cells (<a href="http://www.pengoworks.com/workshop/jquery/tablesorter/tablesorter.htm">original demo</a>). This option is available in the original plugin.</li>
|
||||
<li>The filter widget will work with the original tablesorter plugin, just include the jquery.tablesorter.widget.js file and initialize the widget as seen below.</li>
|
||||
<li><del>Combining the filter widget and pager plugin will not work as expected</del>.</li>
|
||||
<li><span class="version">v2.21.6</span>,
|
||||
<ul>
|
||||
<li>Added <code>filter_childByColumn</code> to allow filtering to work on child row columns. See the <a href="#child-by-column">By Column</a> demo below.</li>
|
||||
<li>Extra white-space was added after each line in the child row content to account for the loss of white-space which occurs while processing cell content using <code>textContent</code>.</li>
|
||||
<li><span class="label warning">*NOTE*</span> Start getting in the habit of using a class name to hide content as <strong>jQuery 3.0+ will likely change how <code>show()</code> & <code>hide()</code> work</strong> (<a href="https://github.com/jquery/jquery/issues/2308">ref</a>).</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
</li>
|
||||
<li>As of <span class="version updated">v2.15.12</span>,
|
||||
<ul>
|
||||
<li>This demo includes the pager widget.</li>
|
||||
<li>For now, when combining the filter widget with pager, ensure the <code>removeRows</code> option is set to <code>false</code>.</li>
|
||||
<li>Parents of child rows now have a <code>tablesorter-hasChildRow</code> class name added.</li>
|
||||
<li>The last row of each page now includes any child rows. For example, on page 1, click on the "SO71783" row link and the associated child row will now show, as it should</li>
|
||||
<li><span class="label label-info">NOTE!</span> A new css definition was added to every default theme; the "filtered" class name (set by the <code>filter_filteredRow</code> widgetOption) has been added to properly hide/show child rows when filtered.</li>
|
||||
<li>The additional code to always hide child row cells on <code>pagerChange</code> is no longer needed.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Click the link in the Order # column to reveal the hidden child row cells (<a href="http://www.pengoworks.com/workshop/jquery/tablesorter/tablesorter.htm">original demo</a>). This option is available in the original plugin.</li>
|
||||
<li>The filter widget will <strong>NOT work</strong> with the original tablesorter plugin.</li>
|
||||
</ul>
|
||||
<p>
|
||||
</div>
|
||||
|
||||
<h1>Demo</h1>
|
||||
<br>
|
||||
<button type="button" class="toggle-option">Toggle Child Row Content</button> : <span class="state">true</span>
|
||||
Filter Child Row: <a href="#combined">Combined/Disabled</a> | <a href="#child-by-column">By Column</a>
|
||||
<p></p>
|
||||
<h3 id="combined">Combined Child Row Content</h3>
|
||||
<button type="button" class="toggle-combined">Toggle</button> <code>filter_childRows</code> : <span class="state1">true</span>
|
||||
|
||||
<ul>
|
||||
<li>If true, the child row content is included in ALL filters. Enter "cal" (california) in any column filter and the same rows show up.</li>
|
||||
<li>When false, child row content is ignored. Enter "cal" and no rows will be found.</li>
|
||||
<li>If true, the child row content is included in ALL filters. Enter "cali" (california) in any column filter and the same rows show up.</li>
|
||||
<li>When false, child row content is ignored. Enter "cali" and no rows will be found.</li>
|
||||
</ul>
|
||||
|
||||
<div class="pager">
|
||||
@ -134,7 +238,7 @@
|
||||
<select class="gotoPage" title="Select page number"></select>
|
||||
</div>
|
||||
|
||||
<table class="tablesorter">
|
||||
<table id="table1">
|
||||
<colgroup>
|
||||
<col width="85" />
|
||||
<col width="250" />
|
||||
@ -466,6 +570,59 @@
|
||||
</div></pre>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3 id="child-by-column">childByColumn</h3>
|
||||
<button class="toggle-byColumn" type="button">Toggle</button> <code>filter_childByColumn</code> : <span class="state2">true</span>
|
||||
<ul>
|
||||
<li>This option requires the <code>filter_childRow</code> option to be set to <code>true</code> in order to work.</li>
|
||||
<li>If <code>true</code>, child row content can be filtered in the same manner as regular rows. Try searching for values <button data-column="1"><1000</button> in the "FastCar" column, or values between <button data-column="2">3000 - 4000</button> in the "RapidZoo" column. Only one match in a child row is required to show the entire parent/child group.</li>
|
||||
<li>If <code>false</code>, child row content will be grouped together and included in any column search; as was the behavior before this option was added.</li>
|
||||
<li>Extra css was added to override the theme row highlighting to group parent/child highlighting; it just doesn't look that good and it may be removed from the themes in the future.</li>
|
||||
</ul>
|
||||
<button type="button" class="reset">Reset Search</button>
|
||||
<div id="demo"><table id="table2" class="tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Region</th>
|
||||
<th class="sorter-currency">FastCar</th>
|
||||
<th class="sorter-currency">RapidZoo</th>
|
||||
<th class="sorter-currency">SuperGlue</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><a href="#" class="toggle">Middle</a></td><td>FCIDM2015Q1</td><td>RZIDM2015Q1</td><td>SGIDM2015Q1</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Joseph</td><td>$ 423</td><td>$ 182</td><td>$ 255</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Lawrence</td><td>$ 1,908</td><td>$ 1,642</td><td>$ 2,593</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Maria</td><td>$ 1,502</td><td>$ 1,969</td><td>$ 3,408</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Matt</td><td>$ 1,170</td><td>$ 1,093</td><td>$ 2,039</td></tr>
|
||||
<tr><td><a href="#" class="toggle">North</a></td><td>FCIDN2015Q1</td><td>RZIDN2015Q1</td><td>SGIDN2015Q1</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Joseph</td><td>$ 3,643</td><td>$ 2,846</td><td>$ 1,574</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Lawrence</td><td>$ 3,456</td><td>$ 2,658</td><td>$ 1,685</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Maria</td><td>$ 3,235</td><td>$ 2,616.99</td><td>$ 1,612.33</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Matt</td><td>$ 3,868</td><td>$ 2,926</td><td>$ 1,254</td></tr>
|
||||
<tr><td><a href="#" class="toggle">West</a></td><td>FCIDW2015Q1</td><td>RZIDW2015Q1</td><td>SGIDW2015Q1</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Joseph</td><td>$ 5,507</td><td>$ 3,186</td><td>$ 4,882</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Lawrence</td><td>$ 4,082</td><td>$ 4,272</td><td>$ 6,124</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Maria</td><td>$ 5,520</td><td>$ 4,461</td><td>$ 4,872</td></tr>
|
||||
<tr class="tablesorter-childRow"><td>Matt</td><td>$ 5,737</td><td>$ 4,598</td><td>$ 4,233</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h1>CSS</h1>
|
||||
<div id="css">
|
||||
<pre class="prettyprint lang-css"></pre>
|
||||
</div>
|
||||
<h1>Javascript</h1>
|
||||
<div id="javascript2">
|
||||
<pre class="prettyprint lang-javascript"></pre>
|
||||
</div>
|
||||
<h1>HTML</h1>
|
||||
<div id="html">
|
||||
<pre class="prettyprint lang-html"></pre>
|
||||
</div>
|
||||
|
||||
<div class="next-up">
|
||||
<hr />
|
||||
Next up: <a href="example-option-sort-order.html">Set an initial sorting order direction ››</a>
|
||||
|
@ -80,11 +80,11 @@
|
||||
<li>This is a demo of the <a href="index.html#widget-filter-external"><code>filter_external</code></a> option (added <span class="version">v2.15</span>).</li>
|
||||
<li>In <span class="version">v2.15</span>
|
||||
<ul>
|
||||
<li>The <a class="alert" href="index.html#widget-filter-any-match"><code>filter_anyMatch</code></a> has been <span class="label alert">removed</span> (added <span class="version">v2.13.3</span>; removed in v2.15)</li>
|
||||
<li>The <a class="alert" href="index.html#widget-filter-any-match"><code>filter_anyMatch</code></a> option has been <span class="label alert">removed</span> (added <span class="version">v2.13.3</span>; removed in v2.15)</li>
|
||||
<li>A new option <code>filter_external</code> has been added. It is set to a jQuery selector string (<code>'.search'</code>) or jQuery object (<code>$('.search')</code>) targeting an external input.</li>
|
||||
<li>So now a table can include <em>both</em> a filter row (<code>filter_columnFilters</code> is <code>true</code>, i.e. the internal table filters) and any number of external search inputs (as set by the <code>filter_external</code> option).</li>
|
||||
<li>The external search results must have a <code>data-column="#"</code> attribute set, where <code>#</code> is the index of the column (zero-based) that the input targets, to have an input search all table content, set the data column attribute to <code>"all"</code> to match any column.</li>
|
||||
<li>The <a href="index.html#function-bindsearch"><code>$.tablesorter.bindSearch</code> function</a> (<a href="example-widget-filter-external-inputs.html">see demo</a>) does exactly the same thing as the <code>filter_external</code> option. The major difference is seen when using ajax to populate the table, the initial filter values can be set before tablesorter initialization when using teh <code>filter_external</code> option; whereas, the bind search function can not set initial filter values and is usually executed after tablesorter initialization.</li>
|
||||
<li>The <a href="index.html#function-bindsearch"><code>$.tablesorter.bindSearch</code> function</a> (<a href="example-widget-filter-external-inputs.html">see demo</a>) does exactly the same thing as the <code>filter_external</code> option. The major difference is seen when using ajax to populate the table, the initial filter values can be set before tablesorter initialization when using the <code>filter_external</code> option; whereas, the bind search function can not set initial filter values and is usually executed after tablesorter initialization.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -319,7 +319,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li>The <strong>config (c)</strong> is the <code>table.config</code> (added <span class="version">v2.21.0</span>).</li>
|
||||
<li>The <strong>data</strong> parameter is the same data passed to the filter types (see <a href="example-widget-filter-custom-search.html#how_to_add_custom_filter_types">all the data values here</a>).</li>
|
||||
<li>The <strong>data</strong> parameter is the same data passed to the filter types (see <a href="example-widget-filter-custom-search.html#how_to_add_custom_filter_types">all the data values here</a>; added <span class="version">v2.21.6</span>).</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,6 +47,9 @@
|
||||
// visible; default is false
|
||||
filter_childRows : false,
|
||||
|
||||
// if true, filter child row content by column; filter_childRows must also be true
|
||||
filter_childByColumn : false,
|
||||
|
||||
// if true, a filter will be added to the top of each table column;
|
||||
// disabled by using -> headers: { 1: { filter: false } } OR add class="filter-false"
|
||||
// if you set this to false, make sure you perform a search using the second method below
|
||||
@ -222,7 +225,23 @@ $(function(){
|
||||
<h3 id="notes"><a href="#">Notes</a></h3>
|
||||
<div>
|
||||
<ul>
|
||||
<li>In <span class="version">v2.21.6</span>
|
||||
<ul>
|
||||
<li>Regex filter searches now cache the created regex object for each query to optimize speed & a regex search now properly uses case-sensitive content.</li>
|
||||
<li>Add <code>data</code> parameter to <code>filter_functions</code> (<a href="example-widget-filter-custom-search.html#how_to_add_custom_filter_types">get more details</a>).</li>
|
||||
<li>Any match searches which target specific columns will no longer save each filter to its respective column; see <a href="example-widget-filter-any-match.html#anymatch_searches">"AnyMatch Searches"</a> documentation.</li>
|
||||
<li>Operator filter searchs now ignore empty strings (because <code>"" < 10</code> is <code>true</code>).</li>
|
||||
<li>Added <code>filter_childByColumn</code> option which allows the filtering columns in both the parent & child rows. Demo added to the <a href="example-child-rows-filtered.html#child-by-column">filtered child rows demo</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>In <span class="version updated">v2.18.0</span>, added <code>filter_cellFilter</code> & the ability to set multiple "any" match columns for an external search (see the <a href="example-widget-filter-external-inputs.html">external inputs demo</a> for more details).</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="accordion start-closed">
|
||||
<h3 id="old-notes"><a href="#">Older Notes</a></h3>
|
||||
<div>
|
||||
<ul>
|
||||
<li>In <span class="version">v2.17.8</span>, filter selects will default to exact matches unless the header cell has a "filter-match" class added.</li>
|
||||
<li>In <span class="version">v2.17.1</span>, added a not exact match (<code>!=</code>) filter type.</li>
|
||||
<li>In <span class="version updated">v2.16+</span>,
|
||||
@ -241,9 +260,14 @@ $(function(){
|
||||
</ul>
|
||||
</li>
|
||||
<li>Added & set <code>filter_saveFilters</code> to <code>true</code> (default is <code>false</code>) in this demo (<span class="version">v2.14</span>).</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>Hover over the grey bar below the table header to open the filter row. Disable this by setting <code>filter_hideFilters</code> option to <code>false</code>.</li>
|
||||
<li>This widget uses jQuery's <code>.nextUntil()</code> function which is only available is jQuery version 1.4+.</li>
|
||||
<li>This widget does work with tablesorter v2.0.5.</li>
|
||||
<li>This widget <em>does NOT</em> work with tablesorter v2.0.5.</li>
|
||||
<li>Using the built-in filters (<a href="example-widget-filter-custom-search.html">learn how to customize them here</a> - demo created <span class="version">v2.17.5</span>):
|
||||
<table class="tablesorter-blue notes">
|
||||
<thead>
|
||||
@ -278,6 +302,7 @@ $(function(){
|
||||
<h3><a href="#">Options</a></h3>
|
||||
<div>
|
||||
<h4>Filter widget defaults (added inside of tablesorter <code>widgetOptions</code>)</h4>
|
||||
<h5>This table includes very basic information about the filter options. For more extensive information & links to demos, see the main page <a href="index.html#Widget-options">Widget & Pager Options</a> section.</h5>
|
||||
<div>
|
||||
<span class="label label-info">TIP!</span> Click on the link in the function column to reveal full details (or <a href="#" class="toggleAll">toggle</a>|<a href="#" class="showAll">show</a>|<a href="#" class="hideAll">hide</a> all) or double click to update the browser location.
|
||||
</div>
|
||||
@ -293,6 +318,19 @@ $(function(){
|
||||
<td>if <code>true</code>, filter includes child row content in the search.</td>
|
||||
</tr>
|
||||
|
||||
<tr id="filter-child-by-column">
|
||||
<td><a href="#" class="permalink">filter_childByColumn</a></td>
|
||||
<td>false</td>
|
||||
<td>if <code>true</code>, queries will search child row content by column (<span class="version">v2.21.6</span>).
|
||||
<div class="collapsible">
|
||||
<br>
|
||||
The <code>filter_childRows</code> option must be <code>true</code> for this option to work.<br>
|
||||
<br>
|
||||
If <code>false</code>, and the <code>filter_childRows</code> option is <code>true</code>, then queries in <em>any column</em> will search all child content, as before this option was added.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="filter-column-filters">
|
||||
<td><span class="permalink">filter_columnFilters</span></td>
|
||||
<td>true</td>
|
||||
|
@ -364,7 +364,7 @@
|
||||
<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.15.12</span>)</li>
|
||||
<li><a href="example-child-rows-filtered.html">Use child rows + filter widget</a> (<span class="updated version">v2.21.6</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>
|
||||
@ -484,9 +484,9 @@
|
||||
<li><span class="results">†</span> Filter Widget (<span class="version updated">v2.21.6</span>):
|
||||
<ul>
|
||||
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.18.1</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.20.0</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.21.6</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.21.0</span>)</li>
|
||||
<li><a href="example-widget-filter-custom.html">custom</a> (v2.3.6; <span class="version updated">v2.21.6</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.21.6</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.21.0</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>
|
||||
@ -535,18 +535,18 @@
|
||||
<ul>
|
||||
<li><a href="example-parsers-duration.html">Countdown parser</a> (<span class="version">v2.19.0</span>).</li>
|
||||
<li><a href="example-parsers-dates.html">Date parsers</a> (<span class="version">v2.8</span>; <span class="version updated">v2.18.0</span>; includes weekday, month, two-digit year & <a href="http://sugarjs.com/dates">sugar.js</a> date parsers).</li>
|
||||
<li><a href="example-parsers-date-range.html">Date Range parsers</a> (<span class="version">v2.21.0</span>); if filters, include the <a href="example-widget-filter-custom-search2.html">insideRange</a> filter search type.</li>
|
||||
<li><a href="example-parsers-date-range.html">Date range parsers</a> (<span class="version">v2.21.0</span>); if filters, include the <a href="example-widget-filter-custom-search2.html">insideRange</a> filter search type.</li>
|
||||
<li><a href="example-parsers-duration.html">Duration parser</a> (<span class="version">v2.17.8</span>).</li>
|
||||
<li><a href="example-parsers-file-type.html">File type parser</a> (<span class="version">v2.13</span>).</li>
|
||||
<li><a href="http://jsfiddle.net/Mottie/0j18Lw8r/">jQuery Globalize</a> (number & date parsers; <span class="version">v2.21.6</span>).</li>
|
||||
<li><a href="example-parsers-ignore-articles.html">Ignore leading articles parser</a> (Ignore "A", "An" and "The" in titles) (<span class="version">v2.8</span>).</li>
|
||||
<li><a href="example-widget-grouping.html">Input/select parsers</a> (used by Grouping rows widget) (<span class="version">v2.8</span>; <span class="version updated">v2.21.3</span>).</li>
|
||||
<li><a href="example-parsers-feet-inch-fraction.html">Feet-inch-fraction parser</a> (<span class="version">v2.8</span>).</li>
|
||||
<li><a href="example-parsers-file-type.html">File type parser</a> (<span class="version">v2.13</span>).</li>
|
||||
<li><a href="example-parsers-ignore-articles.html">Ignore leading articles parser</a> (Ignore "A", "An" and "The" in titles) (<span class="version">v2.8</span>).</li>
|
||||
<li><a href="example-widget-grouping.html">Input/select parsers</a> (used by Grouping rows widget) (<span class="version">v2.8</span>; <span class="version updated">v2.21.6</span>).</li>
|
||||
<li><a href="http://jsfiddle.net/Mottie/0j18Lw8r/">jQuery Globalize</a> (number & date parsers; <span class="version">v2.21.6</span>).</li>
|
||||
<li><a href="example-parsers-metric.html">Metric parser</a> (<span class="version">v2.8</span>).</li>
|
||||
<li><a href="example-parsers-named-numbers.html">Named Numbers parser</a> (<span class="version">v2.18.0</span>).</li>
|
||||
<li><a href="example-parsers-ip-address.html">Network (IPv4, IPv6 and MAC address parser</a> (<span class="version">v2.12</span>; <span class="version updated">v2.18.0</span>).</li>
|
||||
<li><a href="example-parsers-named-numbers.html">Named Numbers parser</a> (<span class="version">v2.18.0</span>; <span class="version updated">v2.21.6</span>).</li>
|
||||
<li><a href="example-parsers-ip-address.html">Network (IPv4, IPv6 and MAC address parser</a> (<span class="version">v2.12</span>; <span class="version updated">v2.21.6</span>).</li>
|
||||
<li><a href="example-parsers-roman.html">Roman Numeral parser</a> (<span class="version">v2.17.3</span>).</li>
|
||||
<li><a href="example-option-textsorter-semver.html">Semantic Versioning (Semver) sorting</a> (<span class="version">v2.14.3</span>).</li>
|
||||
<li><a href="example-option-textsorter-semver.html">Semantic Versioning (Semver) sorting</a> (<span class="version">v2.14.3</span>; <span class="version updated">v2.21.4</span>).</li>
|
||||
</ul>
|
||||
|
||||
<h4>Work-in-progress</h4>
|
||||
@ -1862,6 +1862,8 @@ $(function(){
|
||||
// filter_anyMatch : null, // THIS OPTION WAS REMOVED IN V2.15
|
||||
// Include child rows content in the search
|
||||
filter_childRows : false,
|
||||
// filter child row content by column, if true; filter_childRows must also be true!
|
||||
filter_childByColumn : false,
|
||||
// show column filters
|
||||
filter_columnFilters : true,
|
||||
// css class name added to the filter cell (string or array)
|
||||
@ -2254,8 +2256,8 @@ $(function(){
|
||||
Filter widget: If there are child rows in the table (rows with class name from <a href="#csschildrow"><code>"cssChildRow"</code></a> option) and this option is <code>true</code> and a match is found anywhere in the child row, then it will make that row visible.
|
||||
(Modified v2.1).
|
||||
<div class="collapsible">
|
||||
<br>
|
||||
Use the <a href="#widget-filter-childrows"><code>filter_childRows</code></a> option include child row text as follows:
|
||||
<p><span class="label label-info">*NOTE*</span> When using this option, please be aware that all child row content will be obtained from each table cell using <code>textContent</code>, so none of the markup will be preserved. Also, carriage returns (<code><br></code>) will not be included. To account for the loss of white space, especially after carriage returns, please add an extra space to the end of the line. Using <code>innerText</code>, could have been an option for preserving the white space, but it is not standardized across all browsers (<a href="http://perfectionkills.com/the-poor-misunderstood-innerText/">ref</a>).</p>
|
||||
Use the <a href="#widget-filter-childrows"><code>filter_childRows</code></a> option to include child row text as follows:
|
||||
<pre class="prettyprint lang-js">$(function(){
|
||||
$("table").tablesorter({
|
||||
widgets: ["filter"],
|
||||
@ -2268,6 +2270,31 @@ $(function(){
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr id="widget-filter-child-by-column">
|
||||
<td><a href="#" class="permalink">filter_childByColumn</a></td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>
|
||||
Filter widget: If <code>true</code>, queries will search child row content by column (<span class="version">v2.21.6</span>).
|
||||
<div class="collapsible">
|
||||
<p>The <code>filter_childRows</code> option must also be <code>true</code> for this option to work.</p>
|
||||
<p>If <code>false</code>, and the <code>filter_childRows</code> option is <code>true</code>, then queries in <em>any column</em> will search all child content, as before this option was added.</p>
|
||||
<p></p>
|
||||
Use the <a href="#widget-filter-child-by-column"><code>filter_childByColumn</code></a> option as follows:
|
||||
<pre class="prettyprint lang-js">$(function(){
|
||||
$("table").tablesorter({
|
||||
widgets: ["filter"],
|
||||
widgetOptions : {
|
||||
filter_childRows : true,
|
||||
filter_childByColumn : true
|
||||
}
|
||||
});
|
||||
});</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td><a href="example-child-rows-filtered.html#child-by-column">Example</a></td>
|
||||
</tr>
|
||||
|
||||
<tr id="widget-filter-columnFilters">
|
||||
<td><a href="#" class="permalink">filter_columnFilters</a></td>
|
||||
<td>Boolean</td>
|
||||
|
@ -21,6 +21,9 @@
|
||||
if ($("#js").length) {
|
||||
$("#javascript pre").addClass('mod').html( cleanupCode( $("#js").html() ) );
|
||||
}
|
||||
if ($("#js2").length) {
|
||||
$("#javascript2 pre").addClass('mod').html( cleanupCode( $("#js2").html() ) );
|
||||
}
|
||||
if ($("#css").length) {
|
||||
$("pre.lang-css").addClass('mod').html( cleanupCode( $("#css").html() ) );
|
||||
}
|
||||
@ -117,7 +120,7 @@
|
||||
$t.each(function(i){
|
||||
var $this = $(this);
|
||||
$this.accordion({
|
||||
active: hashId,
|
||||
active: $this.hasClass('start-closed') ? false : hashId,
|
||||
animate: false,
|
||||
heightStyle: 'content',
|
||||
collapsible: true,
|
||||
|
@ -19,6 +19,7 @@ ts.addWidget({
|
||||
priority: 50,
|
||||
options : {
|
||||
filter_childRows : false, // if true, filter includes child row content in the search
|
||||
filter_childByColumn : false, // (filter_childRows must be true) if true = search child rows by column; false = search all child row text grouped
|
||||
filter_columnFilters : true, // if true, a filter will be added to the top of each table column
|
||||
filter_columnAnyMatch: true, // if true, allows using "#:{query}" in AnyMatch searches (column:query)
|
||||
filter_cellFilter : '', // css class name added to the filter cell (string or array)
|
||||
@ -89,11 +90,15 @@ ts.filter = {
|
||||
},
|
||||
// function( c, data ) { }
|
||||
// c = table.config
|
||||
// data.filter = array of filter input values;
|
||||
// data.iFilter = same array, except lowercase (if wo.filter_ignoreCase is true)
|
||||
// data.$row = jQuery object of the row currently being processed
|
||||
// data.$cells = jQuery object of all cells within the current row
|
||||
// data.filters = array of filters for all columns (some may be undefined)
|
||||
// data.filter = filter for the current column
|
||||
// data.iFilter = same as data.filter, except lowercase (if wo.filter_ignoreCase is true)
|
||||
// data.exact = table cell text (or parsed data if column parser enabled)
|
||||
// data.iExact = same as data.exact, except lowercase (if wo.filter_ignoreCase is true)
|
||||
// data.cache = table cell text from cache, so it has been parsed (& in all lower case if config.ignoreCase is true)
|
||||
// data.cache = table cell text from cache, so it has been parsed (& in all lower case if c.ignoreCase is true)
|
||||
// data.cacheArray = An array of parsed content from each table cell in the row being processed
|
||||
// data.index = column index; table = table element (DOM)
|
||||
// data.parsed = array (by column) of boolean values (from filter_useParsedData or "filter-parsed" class)
|
||||
types: {
|
||||
@ -101,15 +106,14 @@ ts.filter = {
|
||||
regex: function( c, data ) {
|
||||
if ( ts.filter.regex.regex.test(data.filter) ) {
|
||||
var matches,
|
||||
wo = c.widgetOptions,
|
||||
// cache regex per column for optimal speed
|
||||
regex = wo.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
|
||||
regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
|
||||
isRegex = regex instanceof RegExp;
|
||||
try {
|
||||
if (!isRegex) {
|
||||
// force case insensitive search if ignoreCase option set?
|
||||
// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
|
||||
wo.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
|
||||
data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
|
||||
}
|
||||
matches = regex.test( data.exact );
|
||||
} catch (error) {
|
||||
@ -135,13 +139,11 @@ ts.filter = {
|
||||
result = ts.filter.parseFilter(c, $.trim('' + data.iFilter.replace(ts.filter.regex.operators, '')), index, true);
|
||||
query = ( typeof result === "number" && result !== '' && !isNaN(result) ) ? result : query;
|
||||
}
|
||||
|
||||
// iExact may be numeric - see issue #149;
|
||||
// check if cached is defined, because sometimes j goes out of range? (numeric columns)
|
||||
cachedValue = ( parsed || parser.type === 'numeric' ) && !isNaN(query) && typeof data.cache !== 'undefined' ? data.cache :
|
||||
isNaN(data.iExact) ? ts.formatFloat( data.iExact.replace(ts.filter.regex.nondigit, ''), table) :
|
||||
ts.formatFloat( data.iExact, table );
|
||||
|
||||
if ( />/.test(data.iFilter) ) { result = />=/.test(data.iFilter) ? cachedValue >= query : cachedValue > query; }
|
||||
if ( /</.test(data.iFilter) ) { result = /<=/.test(data.iFilter) ? cachedValue <= query : cachedValue < query; }
|
||||
// keep showing all rows if nothing follows the operator
|
||||
@ -271,7 +273,6 @@ ts.filter = {
|
||||
wo.filter_initTimer = null;
|
||||
wo.filter_formatterCount = 0;
|
||||
wo.filter_formatterInit = [];
|
||||
wo.filter_regexCache = [];
|
||||
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
|
||||
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
|
||||
|
||||
@ -793,43 +794,200 @@ ts.filter = {
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
processRow: function( c, data, vars ) {
|
||||
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, fxn, ffxn, txt,
|
||||
regex = ts.filter.regex,
|
||||
wo = c.widgetOptions,
|
||||
showRow = true;
|
||||
data.$cells = data.$row.children();
|
||||
|
||||
if ( data.anyMatchFlag ) {
|
||||
// look for multiple columns "1-3,4-6,8"
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.rowArray = data.$cells.map(function(i){
|
||||
if ( $.inArray(i, columnIndex) > -1 ) {
|
||||
if (data.parsed[i]) {
|
||||
txt = data.cacheArray[i];
|
||||
} else {
|
||||
txt = data.rawArray[i];
|
||||
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
|
||||
if (c.sortLocaleCompare) {
|
||||
txt = ts.replaceAccents(txt);
|
||||
}
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
}).get();
|
||||
data.filter = data.anyMatchFilter;
|
||||
data.iFilter = data.iAnyMatchFilter;
|
||||
data.exact = data.rowArray.join(' ');
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice(0,-1).join(' ');
|
||||
filterMatched = null;
|
||||
matches = null;
|
||||
for (ffxn in ts.filter.types) {
|
||||
if ($.inArray(ffxn, vars.noAnyMatch) < 0 && matches === null) {
|
||||
matches = ts.filter.types[ffxn]( c, data );
|
||||
if (matches !== null) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filterMatched !== null) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
if ( wo.filter_startsWith ) {
|
||||
showRow = false;
|
||||
columnIndex = c.columns;
|
||||
while ( !showRow && columnIndex > 0 ) {
|
||||
columnIndex--;
|
||||
showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
|
||||
}
|
||||
} else {
|
||||
showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
|
||||
}
|
||||
}
|
||||
data.anyMatch = false;
|
||||
// no other filters to process
|
||||
if ( data.filters.join( '' ) === data.filter ) {
|
||||
return showRow;
|
||||
}
|
||||
}
|
||||
|
||||
for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
|
||||
data.filter = data.filters[ columnIndex ];
|
||||
data.index = columnIndex;
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if ( data.filter ) {
|
||||
data.cache = data.cacheArray[ columnIndex ];
|
||||
// check if column data should be from the cell or from parsed data
|
||||
if ( wo.filter_useParsedData || data.parsed[ columnIndex ] ) {
|
||||
data.exact = data.cache;
|
||||
} else {
|
||||
result = data.rawArray[ columnIndex ] || '';
|
||||
data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
|
||||
}
|
||||
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
||||
data.exact.toLowerCase() : data.exact;
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text "a - z|A through Z"
|
||||
ffxn = wo.filter_columnFilters ?
|
||||
c.$filters.add( c.$externalFilters )
|
||||
.filter( '[data-column="'+ columnIndex + '"]' )
|
||||
.find( 'select option:selected' )
|
||||
.attr( 'data-function-name' ) || '' : '';
|
||||
// replace accents - see #357
|
||||
if ( c.sortLocaleCompare ) {
|
||||
data.filter = ts.replaceAccents( data.filter );
|
||||
}
|
||||
|
||||
val = true;
|
||||
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
|
||||
data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
|
||||
// val is used to indicate that a filter select is using a default filter;
|
||||
// so we override the exact & partial matches
|
||||
val = false;
|
||||
}
|
||||
// data.iFilter = case insensitive (if wo.filter_ignoreCase is true), data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
||||
fxn = vars.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[ columnIndex ];
|
||||
hasSelect = $cell.hasClass( 'filter-select' );
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if ( fxn === true || hasSelect ) {
|
||||
// default selector uses exact match unless "filter-match" class is found
|
||||
filterMatched = ( $cell.hasClass( 'filter-match' ) ) ?
|
||||
data.iExact.search( data.iFilter ) >= 0 : data.filter === data.exact;
|
||||
} else if ( typeof fxn === 'function' ) {
|
||||
// filter callback( exact cell content, parser normalized content,
|
||||
// filter input value, column index, jQuery row object )
|
||||
filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
|
||||
} else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
|
||||
// selector option function
|
||||
filterMatched =
|
||||
fxn[ ffxn || data.filter ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
|
||||
}
|
||||
}
|
||||
if ( filterMatched === null ) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ ffxn ]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( filterMatched !== null ) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
} else {
|
||||
txt = ( data.iExact + data.childRowText )
|
||||
.indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
|
||||
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
|
||||
}
|
||||
} else {
|
||||
result = filterMatched;
|
||||
}
|
||||
showRow = ( result ) ? showRow : false;
|
||||
}
|
||||
}
|
||||
return showRow;
|
||||
},
|
||||
findRows: function( table, filters, combinedFilters ) {
|
||||
if (table.config.lastCombinedFilter === combinedFilters || !table.config.widgetOptions.filter_initialized) { return; }
|
||||
var len, norm_rows, $rows, rowIndex, tbodyIndex, $tbody, $cell, columnIndex,
|
||||
childRow, lastSearch, hasSelect, matches, result, showRow, time, val, indx,
|
||||
notFiltered, searchFiltered, filterMatched, excludeMatch, fxn, ffxn,
|
||||
query, injected, res, id,
|
||||
if ( table.config.lastCombinedFilter === combinedFilters ||
|
||||
!table.config.widgetOptions.filter_initialized ) {
|
||||
return;
|
||||
}
|
||||
var len, norm_rows, rowData, $rows, rowIndex, tbodyIndex, $tbody, columnIndex,
|
||||
isChild, childRow, lastSearch, showRow, time, val, indx,
|
||||
notFiltered, searchFiltered, query, injected, res, id, txt,
|
||||
storedFilters = $.extend( [], filters ),
|
||||
regex = ts.filter.regex,
|
||||
c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
// data object passed to filters; anyMatch is a flag for the filters
|
||||
data = { anyMatch: false, filters: filters },
|
||||
data = {
|
||||
anyMatch: false,
|
||||
filters: filters,
|
||||
// regex filter type cache
|
||||
filter_regexCache : [],
|
||||
},
|
||||
vars = {
|
||||
// anyMatch really screws up with these types of filters
|
||||
noAnyMatch = [ 'range', 'notMatch', 'operators' ];
|
||||
|
||||
// clear regex cache prior to each search
|
||||
wo.filter_regexCache = [];
|
||||
|
||||
// parse columns after formatter, in case the class is added at that point
|
||||
data.parsed = c.$headers.map(function(columnIndex) {
|
||||
return c.parsers && c.parsers[columnIndex] && c.parsers[columnIndex].parsed ||
|
||||
// getData won't return "parsed" if other "filter-" class names exist (e.g. <th class="filter-select filter-parsed">)
|
||||
ts.getData && ts.getData(c.$headerIndexed[columnIndex], ts.getColumnData( table, c.headers, columnIndex ), 'filter') === 'parsed' ||
|
||||
$(this).hasClass('filter-parsed');
|
||||
}).get();
|
||||
|
||||
noAnyMatch: [ 'range', 'notMatch', 'operators' ],
|
||||
// cache filter variables that use ts.getColumnData in the main loop
|
||||
wo.filter_indexed = {
|
||||
functions : [],
|
||||
excludeFilter : [],
|
||||
defaultColFilter : [],
|
||||
defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
|
||||
};
|
||||
|
||||
// parse columns after formatter, in case the class is added at that point
|
||||
data.parsed = c.$headers.map( function( columnIndex ) {
|
||||
return c.parsers && c.parsers[ columnIndex ] &&
|
||||
// force parsing if parser type is numeric
|
||||
( c.parsers[ columnIndex ].parsed || c.parsers[ columnIndex ].type === 'numeric' ) ||
|
||||
// getData won't return "parsed" if other "filter-" class names exist
|
||||
// (e.g. <th class="filter-select filter-parsed">)
|
||||
ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
|
||||
ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
|
||||
$( this ).hasClass( 'filter-parsed' );
|
||||
}).get();
|
||||
|
||||
for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
|
||||
wo.filter_indexed.functions[ columnIndex ] = ts.getColumnData( table, wo.filter_functions, columnIndex );
|
||||
wo.filter_indexed.defaultColFilter[ columnIndex ] = ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
|
||||
wo.filter_indexed.excludeFilter[ columnIndex ] = ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split(/\s+/);
|
||||
vars.functions[ columnIndex ] = ts.getColumnData( table, wo.filter_functions, columnIndex );
|
||||
vars.defaultColFilter[ columnIndex ] = ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
|
||||
vars.excludeFilter[ columnIndex ] = ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split(/\s+/);
|
||||
}
|
||||
|
||||
if (c.debug) {
|
||||
@ -860,10 +1018,10 @@ ts.filter = {
|
||||
|
||||
if ( (wo.filter_$anyMatch && wo.filter_$anyMatch.length) || typeof filters[c.columns] !== 'undefined' ) {
|
||||
data.anyMatchFlag = true;
|
||||
data.anyMatchFilter = wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() || ( '' + filters[c.columns] ) || '';
|
||||
data.anyMatchFilter = '' + ( filters[c.columns] || wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() || '' );
|
||||
if (wo.filter_columnAnyMatch) {
|
||||
// specific columns search
|
||||
query = data.anyMatchFilter.split( ts.filter.regex.andSplit );
|
||||
query = data.anyMatchFilter.split( regex.andSplit );
|
||||
injected = false;
|
||||
for (indx = 0; indx < query.length; indx++) {
|
||||
res = query[indx].split(':');
|
||||
@ -918,169 +1076,68 @@ ts.filter = {
|
||||
// replace accents
|
||||
data.anyMatchFilter = ts.replaceAccents(data.anyMatchFilter);
|
||||
}
|
||||
if ( wo.filter_defaultFilter && regex.iQuery.test( wo.filter_indexed.defaultAnyFilter ) ) {
|
||||
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, wo.filter_indexed.defaultAnyFilter );
|
||||
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
|
||||
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
|
||||
// clear search filtered flag because default filters are not saved to the last search
|
||||
searchFiltered = false;
|
||||
}
|
||||
// make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
|
||||
// when c.ignoreCase is true, the cache contains all lower case data
|
||||
data.iAnyMatchFilter = !(wo.filter_ignoreCase && c.ignoreCase) ? data.anyMatchFilter : data.anyMatchFilter.toLocaleLowerCase();
|
||||
data.iAnyMatchFilter = !(wo.filter_ignoreCase && c.ignoreCase) ? data.anyMatchFilter : data.anyMatchFilter.toLowerCase();
|
||||
}
|
||||
|
||||
// loop through the rows
|
||||
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
||||
|
||||
data.cacheArray = norm_rows[rowIndex];
|
||||
data.rawArray = data.cacheArray[c.columns].raw;
|
||||
data.$row = $rows.eq(rowIndex);
|
||||
data.$cells = data.$row.children();
|
||||
|
||||
childRow = $rows[rowIndex].className;
|
||||
txt = $rows[rowIndex].className;
|
||||
// the first row can never be a child row
|
||||
isChild = rowIndex && regex.child.test(txt);
|
||||
// skip child rows & already filtered rows
|
||||
if ( regex.child.test(childRow) || (searchFiltered && regex.filtered.test(childRow)) ) { continue; }
|
||||
showRow = true;
|
||||
// *** nextAll/nextUntil not supported by Zepto! ***
|
||||
childRow = data.$row.nextUntil('tr:not(.' + c.cssChildRow + ')');
|
||||
if ( isChild || ( searchFiltered && regex.filtered.test( txt ) ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data.$row = $rows.eq( rowIndex );
|
||||
data.cacheArray = norm_rows[ rowIndex ];
|
||||
rowData = data.cacheArray[ c.columns ];
|
||||
data.rawArray = rowData.raw;
|
||||
data.childRowText = '';
|
||||
|
||||
if ( !wo.filter_childByColumn ) {
|
||||
txt = '';
|
||||
// child row cached text
|
||||
childRow = rowData.child;
|
||||
// so, if "table.config.widgetOptions.filter_childRows" is true and there is
|
||||
// a match anywhere in the child row, then it will make the row visible
|
||||
// checked here so the option can be changed dynamically
|
||||
data.childRowText = (childRow.length && wo.filter_childRows) ? childRow.text() : '';
|
||||
data.childRowText = wo.filter_ignoreCase ? data.childRowText.toLocaleLowerCase() : data.childRowText;
|
||||
if (data.anyMatchFlag) {
|
||||
// look for multiple columns "1-3,4-6,8"
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.rowArray = data.$cells.map(function(i){
|
||||
if ( $.inArray(i, columnIndex) > -1 ) {
|
||||
var txt;
|
||||
if (data.parsed[i]) {
|
||||
txt = data.cacheArray[i];
|
||||
} else {
|
||||
txt = data.rawArray[i];
|
||||
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
|
||||
if (c.sortLocaleCompare) {
|
||||
txt = ts.replaceAccents(txt);
|
||||
for (indx = 0; indx < childRow.length; indx++) {
|
||||
txt += ' ' + childRow[indx].join('') || '';
|
||||
}
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
}).get();
|
||||
data.filter = data.anyMatchFilter;
|
||||
data.iFilter = data.iAnyMatchFilter;
|
||||
data.exact = data.rowArray.join(' ');
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice(0,-1).join(' ');
|
||||
filterMatched = null;
|
||||
$.each(ts.filter.types, function(type, typeFunction) {
|
||||
if ($.inArray(type, noAnyMatch) < 0) {
|
||||
matches = typeFunction( c, data );
|
||||
if (matches !== null) {
|
||||
filterMatched = matches;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (filterMatched !== null) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
if (wo.filter_startsWith) {
|
||||
showRow = false;
|
||||
columnIndex = c.columns;
|
||||
while (!showRow && columnIndex > 0) {
|
||||
columnIndex--;
|
||||
showRow = showRow || data.rowArray[columnIndex].indexOf(data.iFilter) === 0;
|
||||
}
|
||||
} else {
|
||||
showRow = (data.iExact + data.childRowText).indexOf(data.iFilter) >= 0;
|
||||
}
|
||||
}
|
||||
data.anyMatch = false;
|
||||
data.childRowText = wo.filter_childRows ?
|
||||
( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
|
||||
'';
|
||||
}
|
||||
|
||||
for (columnIndex = 0; columnIndex < c.columns; columnIndex++) {
|
||||
data.filter = filters[columnIndex];
|
||||
data.index = columnIndex;
|
||||
showRow = ts.filter.processRow( c, data, vars );
|
||||
childRow = rowData.$row.filter(':gt(0)');
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = wo.filter_indexed.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if (data.filter) {
|
||||
data.cache = data.cacheArray[columnIndex];
|
||||
// check if column data should be from the cell or from parsed data
|
||||
if (wo.filter_useParsedData || data.parsed[columnIndex]) {
|
||||
data.exact = data.cache;
|
||||
} else {
|
||||
result = data.rawArray[ columnIndex ] || '';
|
||||
data.exact = c.sortLocaleCompare ? ts.replaceAccents(result) : result; // issue #405
|
||||
}
|
||||
data.iExact = !regex.type.test(typeof data.exact) && wo.filter_ignoreCase ? data.exact.toLocaleLowerCase() : data.exact;
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text "a - z|A through Z"
|
||||
ffxn = wo.filter_columnFilters ?
|
||||
c.$filters.add(c.$externalFilters).filter('[data-column="'+ columnIndex + '"]').find('select option:selected').attr('data-function-name') || '' : '';
|
||||
// replace accents - see #357
|
||||
if (c.sortLocaleCompare) {
|
||||
data.filter = ts.replaceAccents(data.filter);
|
||||
}
|
||||
|
||||
val = true;
|
||||
if (wo.filter_defaultFilter && regex.iQuery.test( wo.filter_indexed.defaultColFilter[ columnIndex ] )) {
|
||||
data.filter = ts.filter.defaultFilter( data.filter, wo.filter_indexed.defaultColFilter[ columnIndex ] );
|
||||
// val is used to indicate that a filter select is using a default filter; so we override the exact & partial matches
|
||||
val = false;
|
||||
}
|
||||
// data.iFilter = case insensitive (if wo.filter_ignoreCase is true), data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? (data.filter || '').toLocaleLowerCase() : data.filter;
|
||||
fxn = wo.filter_indexed.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[columnIndex];
|
||||
hasSelect = $cell.hasClass('filter-select');
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if (fxn === true || hasSelect) {
|
||||
// default selector uses exact match unless "filter-match" class is found
|
||||
filterMatched = ($cell.hasClass('filter-match')) ? data.iExact.search(data.iFilter) >= 0 : data.filter === data.exact;
|
||||
} else if (typeof fxn === 'function') {
|
||||
// filter callback( exact cell content, parser normalized content, filter input value, column index, jQuery row object )
|
||||
filterMatched = fxn(data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
|
||||
} else if (typeof fxn[ffxn || data.filter] === 'function') {
|
||||
// selector option function
|
||||
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
|
||||
if ( wo.filter_childRows && childRow.length ) {
|
||||
if ( wo.filter_childByColumn ) {
|
||||
// cycle through each child row
|
||||
for ( indx = 0; indx < childRow.length; indx++ ) {
|
||||
data.$row = childRow.eq( indx );
|
||||
data.cacheArray = rowData.child[ indx ];
|
||||
data.rawArray = data.cacheArray;
|
||||
// use OR comparison on child rows
|
||||
showRow = showRow || ts.filter.processRow( c, data, vars );
|
||||
}
|
||||
}
|
||||
if (filterMatched === null) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
$.each(ts.filter.types, function(type, typeFunction) {
|
||||
if ($.inArray(type, excludeMatch) < 0) {
|
||||
matches = typeFunction( c, data );
|
||||
if (matches !== null) {
|
||||
filterMatched = matches;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (filterMatched !== null) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
} else {
|
||||
data.exact = (data.iExact + data.childRowText).indexOf( ts.filter.parseFilter(c, data.iFilter, columnIndex, data.parsed[columnIndex]) );
|
||||
result = ( (!wo.filter_startsWith && data.exact >= 0) || (wo.filter_startsWith && data.exact === 0) );
|
||||
}
|
||||
} else {
|
||||
result = filterMatched;
|
||||
}
|
||||
showRow = (result) ? showRow : false;
|
||||
}
|
||||
}
|
||||
data.$row
|
||||
.toggleClass(wo.filter_filteredRow, !showRow)[0]
|
||||
.display = showRow ? '' : 'none';
|
||||
if (childRow.length) {
|
||||
childRow.toggleClass( wo.filter_filteredRow, !showRow );
|
||||
}
|
||||
|
||||
rowData.$row
|
||||
.toggleClass(wo.filter_filteredRow, !showRow)[0]
|
||||
.display = showRow ? '' : 'none';
|
||||
}
|
||||
}
|
||||
c.filteredRows += $rows.not('.' + wo.filter_filteredRow).length;
|
||||
@ -1183,7 +1240,7 @@ ts.filter = {
|
||||
},
|
||||
getOptions: function(table, column, onlyAvail) {
|
||||
table = $(table)[0];
|
||||
var rowIndex, tbodyIndex, len, row, cache, cell,
|
||||
var rowIndex, tbodyIndex, len, row, cache,
|
||||
c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
arry = [];
|
||||
|
@ -9,7 +9,7 @@
|
||||
<script src="testing/qunit-1.16.0.js"></script>
|
||||
<script src="docs/js/jquery-latest.min.js"></script>
|
||||
<script src="js/jquery.tablesorter.js"></script>
|
||||
<script src="js/jquery.tablesorter.widgets.js"></script>
|
||||
<script src="js/widgets/widget-filter.js"></script>
|
||||
<script src="js/parsers/parser-network.js"></script>
|
||||
<script src="js/extras/jquery.metadata.js"></script>
|
||||
<script src="testing/testing.js"></script>
|
||||
|
@ -68,7 +68,7 @@ $(function(){
|
||||
'<tr><td>16</td><td>Jim</td><td>Franco</td><td>24</td><td>$14.19</td><td>14%</td><td>Jan 14, 2004 11:23 AM</td><td>Franco</td></tr>' +
|
||||
'<tr><td>166</td><td>Bruce Lee</td><td>Evans</td><td>22</td><td>$13.19</td><td>11%</td><td>Jan 18, 2007 9:12 AM</td><td>Evans</td></tr>' +
|
||||
'<tr><td>100</td><td>Brenda Dexter</td><td>McMasters</td><td>18</td><td>$55.20</td><td>15%</td><td>Feb 12, 2010 7:23 PM</td><td>McMasters</td></tr>' +
|
||||
'<tr><td>55</td><td>Dennis</td><td>Bronson</td><td>65</td><td>$123.00</td><td>32%</td><td>Jan 20, 2001 1:12 PM</td><td>Bronson</td></tr>' +
|
||||
'<tr><td>55</td><td>Dennis</td><td>Bronson</td><td>65</td><td>$123.00</td><td></td><td>Jan 20, 2001 1:12 PM</td><td>Bronson</td></tr>' +
|
||||
'<tr><td>9</td><td>Martha</td><td>delFuego</td><td>25</td><td>$22.09</td><td>17%</td><td>Jun 11, 2011 10:55 AM</td><td>delFuego</td></tr>' +
|
||||
'</tbody></table>').find('table');
|
||||
this.table = this.$table[0];
|
||||
@ -183,13 +183,13 @@ $(function(){
|
||||
function(){ assert.cacheCompare( table, 4, [153.19, 123], 'search operator (>100); ensure search filtered gets cleared', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', '', '', '', '', '>=20'], true ); },
|
||||
function(){ assert.cacheCompare( table, 5, [22, 20, 25, 44, 44, 32], 'search operator (>=)', true ); }
|
||||
function(){ assert.cacheCompare( table, 5, [22, 20, 25, 44, 44], 'search operator (>=)', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', '', '', '', '', '<10'], true ); },
|
||||
function(){ assert.cacheCompare( table, 5, [5, 4], 'search operator (<10)', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', '', '', '', '', '<100'], true ); },
|
||||
function(){ assert.cacheCompare( table, 5, [22, 5, 18, 20, 25, 44, 44, 4, 14, 11, 15, 32, 17], 'search operator (<100); ensure search filtered gets cleared', true ); }
|
||||
function(){ assert.cacheCompare( table, 5, [22, 5, 18, 20, 25, 44, 44, 4, 14, 11, 15, 17], 'search operator (<100); ensure search filtered gets cleared', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', '', '', '', '', '<=20'], true ); },
|
||||
function(){ assert.cacheCompare( table, 5, [5, 18, 20, 4, 14, 11, 15, 17], 'search operator (<=)', true ); }
|
||||
@ -249,7 +249,7 @@ $(function(){
|
||||
function(){ assert.cacheCompare( table, 1, ['Bruce', 'Alex'], 'search - filter-match removed', true ); }
|
||||
).nextTask( // filter reset
|
||||
function(){ c.$table.trigger('filterReset'); },
|
||||
function(){ assert.cacheCompare( table, 5, [22, 5, 18, 20, 25, 44, 44, 4, 14, 11, 15, 32, 17], 'filterReset', true ); }
|
||||
function(){ assert.cacheCompare( table, 5, [22, 5, 18, 20, 25, 44, 44, 4, 14, 11, 15, '', 17], 'filterReset', true ); }
|
||||
).nextTask( // filter parsed class
|
||||
function(){
|
||||
wo.filter_startsWith = false;
|
||||
|
Loading…
Reference in New Issue
Block a user