mirror of
https://github.com/Mottie/tablesorter.git
synced 2024-11-15 23:54:22 +00:00
Filter: range, not matches & negative values now search all rows. Add filter language option. Fixes #602
This commit is contained in:
parent
c586a329d6
commit
962108db35
@ -35,7 +35,7 @@
|
|||||||
<script id="js">$(function() {
|
<script id="js">$(function() {
|
||||||
|
|
||||||
// call the tablesorter plugin
|
// call the tablesorter plugin
|
||||||
$("table.tablesorter").tablesorter({
|
$("#table").tablesorter({
|
||||||
theme: 'blue',
|
theme: 'blue',
|
||||||
|
|
||||||
// hidden filter input/selects will resize the columns, so try to minimize the change
|
// hidden filter input/selects will resize the columns, so try to minimize the change
|
||||||
@ -134,7 +134,7 @@
|
|||||||
|
|
||||||
filters[col] = txt;
|
filters[col] = txt;
|
||||||
// using "table.hasFilters" here to make sure we aren't targetting a sticky header
|
// using "table.hasFilters" here to make sure we aren't targetting a sticky header
|
||||||
$.tablesorter.setFilters( $('table.hasFilters'), filters, true ); // new v2.9
|
$.tablesorter.setFilters( $('#table'), filters, true ); // new v2.9
|
||||||
|
|
||||||
/** old method (prior to tablsorter v2.9 ***
|
/** old method (prior to tablsorter v2.9 ***
|
||||||
var filters = $('table.tablesorter').find('input.tablesorter-filter');
|
var filters = $('table.tablesorter').find('input.tablesorter-filter');
|
||||||
@ -162,7 +162,7 @@ $(function(){
|
|||||||
|
|
||||||
// *** widgetfilter_startsWith toggle button ***
|
// *** widgetfilter_startsWith toggle button ***
|
||||||
$('button.toggle').click(function(){
|
$('button.toggle').click(function(){
|
||||||
var c = $('table.tablesorter')[0].config,
|
var c = $('#table')[0].config,
|
||||||
$t = $(this),
|
$t = $(this),
|
||||||
// toggle the boolean
|
// toggle the boolean
|
||||||
fsw = !c.widgetOptions.filter_startsWith,
|
fsw = !c.widgetOptions.filter_startsWith,
|
||||||
@ -178,7 +178,7 @@ $(function(){
|
|||||||
$t.find('span').html( $t.hasClass('filter-match') ? '' : ' No' );
|
$t.find('span').html( $t.hasClass('filter-match') ? '' : ' No' );
|
||||||
}
|
}
|
||||||
// update search after option change; add false to trigger to skip search delay
|
// update search after option change; add false to trigger to skip search delay
|
||||||
$('table.tablesorter').trigger('search', false);
|
c.$table.trigger('search', false);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -557,6 +557,24 @@ $(".search").bind('search keyup', function (e) {
|
|||||||
<div class="inner">
|
<div class="inner">
|
||||||
<p>Moved to the wiki pages - <a href="https://github.com/Mottie/tablesorter/wiki/Change3">filter change log</a>.
|
<p>Moved to the wiki pages - <a href="https://github.com/Mottie/tablesorter/wiki/Change3">filter change log</a>.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3><a href="#">Localization</a></h3>
|
||||||
|
<div class="inner">
|
||||||
|
<p>You can now change the language of the searches used within the filter widget. For example, to change the localization to French, do the following:
|
||||||
|
<pre class="prettyprint lang-js">// add French support
|
||||||
|
$.extend($.tablesorter.language, {
|
||||||
|
to : 'à',
|
||||||
|
or : 'ou',
|
||||||
|
and : 'et'
|
||||||
|
});</pre>If you want to support multiple languages, separate the language variables with a vertical bar (<code>|</code>, <kbd>Shift</kbd> + <kbd>\</kbd>):
|
||||||
|
<pre class="prettyprint lang-js">// add French & Spanish support
|
||||||
|
$.extend($.tablesorter.language, {
|
||||||
|
to : 'à|a',
|
||||||
|
or : 'ou|o',
|
||||||
|
and : 'et|y'
|
||||||
|
});</pre><span class="label label-info">Note</span> These changes still require the user to enter spaces in the filter to perform the search, e.g. <code>1 à 10</code> (shows rows with numbers between 1 and 10).
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1>Demo</h1>
|
<h1>Demo</h1>
|
||||||
@ -568,7 +586,7 @@ $(".search").bind('search keyup', function (e) {
|
|||||||
<div id="demo">Search <button type="button" data-filter-column="5" data-filter-text="2?%">2?%</button> in the Discount column<br>
|
<div id="demo">Search <button type="button" data-filter-column="5" data-filter-text="2?%">2?%</button> in the Discount column<br>
|
||||||
<button type="button" class="reset">Reset</button> <!-- targeted by the "filter_reset" option -->
|
<button type="button" class="reset">Reset</button> <!-- targeted by the "filter_reset" option -->
|
||||||
|
|
||||||
<table class="tablesorter">
|
<table id="table" class="tablesorter">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<!-- you can also add a placeholder using script; $('.tablesorter th:eq(0)').data('placeholder', 'hello') -->
|
<!-- you can also add a placeholder using script; $('.tablesorter th:eq(0)').data('placeholder', 'hello') -->
|
||||||
|
@ -462,9 +462,9 @@
|
|||||||
<li><span class="results">†</span> <a href="example-widget-columns.html">Columns Highlight widget</a> (v2.0.17)</li>
|
<li><span class="results">†</span> <a href="example-widget-columns.html">Columns Highlight widget</a> (v2.0.17)</li>
|
||||||
<li><span class="label label-info">Beta</span> <a href="example-widget-column-selector.html">Column Selector widget</a> (<span class="version">v2.15</span>; <span class="version updated">v2.15.7</span>).</li>
|
<li><span class="label label-info">Beta</span> <a href="example-widget-column-selector.html">Column Selector widget</a> (<span class="version">v2.15</span>; <span class="version updated">v2.15.7</span>).</li>
|
||||||
<li><a href="example-widget-editable.html">Content Editable widget</a> (v2.9; <span class="version updated">v2.13.2</span>).</li>
|
<li><a href="example-widget-editable.html">Content Editable widget</a> (v2.9; <span class="version updated">v2.13.2</span>).</li>
|
||||||
<li><span class="results">†</span> Filter Widget (<span class="version updated">v2.16.2</span>):
|
<li><span class="results">†</span> Filter Widget (<span class="version updated">v2.16.3</span>):
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.15</span>)</li>
|
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.16.3</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.15</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.15</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.15</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.15</span>)</li>
|
||||||
<li><a href="example-widget-filter-custom.html">custom</a> (v2.3.6; <span class="version updated">v2.10.1</span>)</li>
|
<li><a href="example-widget-filter-custom.html">custom</a> (v2.3.6; <span class="version updated">v2.10.1</span>)</li>
|
||||||
|
@ -446,7 +446,7 @@ ts.filter = {
|
|||||||
|
|
||||||
// iExact may be numeric - see issue #149;
|
// iExact may be numeric - see issue #149;
|
||||||
// check if cached is defined, because sometimes j goes out of range? (numeric columns)
|
// check if cached is defined, because sometimes j goes out of range? (numeric columns)
|
||||||
cachedValue = ( parsed[index] || parser.type === 'numeric' )&& !isNaN(query) && typeof cached !== 'undefined' ? cached :
|
cachedValue = ( parsed[index] || parser.type === 'numeric' ) && !isNaN(query) && typeof cached !== 'undefined' ? cached :
|
||||||
isNaN(iExact) ? ts.formatFloat( iExact.replace(ts.filter.regex.nondigit, ''), table) :
|
isNaN(iExact) ? ts.formatFloat( iExact.replace(ts.filter.regex.nondigit, ''), table) :
|
||||||
ts.formatFloat( iExact, table );
|
ts.formatFloat( iExact, table );
|
||||||
|
|
||||||
@ -478,8 +478,8 @@ ts.filter = {
|
|||||||
},
|
},
|
||||||
// Look for an AND or && operator (logical and)
|
// Look for an AND or && operator (logical and)
|
||||||
and : function( filter, iFilter, exact, iExact ) {
|
and : function( filter, iFilter, exact, iExact ) {
|
||||||
if ( /\s+(AND|&&)\s+/g.test(filter) ) {
|
if ( ts.filter.regex.andTest.test(filter) ) {
|
||||||
var query = iFilter.split( /(?:\s+(?:and|&&)\s+)/g ),
|
var query = iFilter.split( ts.filter.regex.andSplit ),
|
||||||
result = iExact.search( $.trim(query[0]) ) >= 0,
|
result = iExact.search( $.trim(query[0]) ) >= 0,
|
||||||
indx = query.length - 1;
|
indx = query.length - 1;
|
||||||
while (result && indx) {
|
while (result && indx) {
|
||||||
@ -492,10 +492,11 @@ ts.filter = {
|
|||||||
},
|
},
|
||||||
// Look for a range (using " to " or " - ") - see issue #166; thanks matzhu!
|
// Look for a range (using " to " or " - ") - see issue #166; thanks matzhu!
|
||||||
range : function( filter, iFilter, exact, iExact, cached, index, table, wo, parsed ) {
|
range : function( filter, iFilter, exact, iExact, cached, index, table, wo, parsed ) {
|
||||||
if ( /\s+(-|to)\s+/.test(iFilter) ) {
|
if ( ts.filter.regex.toTest.test(iFilter) ) {
|
||||||
var result, tmp,
|
var result, tmp,
|
||||||
c = table.config,
|
c = table.config,
|
||||||
query = iFilter.split(/(?: - | to )/), // make sure the dash is for a range and not indicating a negative number
|
// make sure the dash is for a range and not indicating a negative number
|
||||||
|
query = iFilter.split( ts.filter.regex.toSplit ),
|
||||||
range1 = ts.formatFloat(query[0].replace(ts.filter.regex.nondigit, ''), table),
|
range1 = ts.formatFloat(query[0].replace(ts.filter.regex.nondigit, ''), table),
|
||||||
range2 = ts.formatFloat(query[1].replace(ts.filter.regex.nondigit, ''), table);
|
range2 = ts.formatFloat(query[1].replace(ts.filter.regex.nondigit, ''), table);
|
||||||
// parse filter value in case we're comparing numbers (dates)
|
// parse filter value in case we're comparing numbers (dates)
|
||||||
@ -515,9 +516,9 @@ ts.filter = {
|
|||||||
},
|
},
|
||||||
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
||||||
wild : function( filter, iFilter, exact, iExact, cached, index, table, wo, parsed, rowArray ) {
|
wild : function( filter, iFilter, exact, iExact, cached, index, table, wo, parsed, rowArray ) {
|
||||||
if ( /[\?|\*]/.test(iFilter) || /\s+OR\s+/i.test(filter) ) {
|
if ( /[\?|\*]/.test(iFilter) || ts.filter.regex.orReplace.test(filter) ) {
|
||||||
var c = table.config,
|
var c = table.config,
|
||||||
query = iFilter.replace(/\s+OR\s+/gi,"|");
|
query = iFilter.replace(ts.filter.regex.orReplace, "|");
|
||||||
// look for an exact match with the "or" unless the "filter-match" class is found
|
// look for an exact match with the "or" unless the "filter-match" class is found
|
||||||
if (!c.$headers.filter('[data-column="' + index + '"]:last').hasClass('filter-match') && /\|/.test(query)) {
|
if (!c.$headers.filter('[data-column="' + index + '"]:last').hasClass('filter-match') && /\|/.test(query)) {
|
||||||
query = $.isArray(rowArray) ? '(' + query + ')' : '^(' + query + ')$';
|
query = $.isArray(rowArray) ? '(' + query + ')' : '^(' + query + ')$';
|
||||||
@ -547,14 +548,30 @@ ts.filter = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
init: function(table, c, wo) {
|
init: function(table, c, wo) {
|
||||||
var options, string, $header, column, filters, time;
|
// filter language options
|
||||||
|
ts.language = $.extend(true, {}, {
|
||||||
|
to : 'to',
|
||||||
|
or : 'or',
|
||||||
|
and : 'and'
|
||||||
|
}, ts.language);
|
||||||
|
|
||||||
|
var options, string, $header, column, filters, time,
|
||||||
|
regex = ts.filter.regex;
|
||||||
if (c.debug) {
|
if (c.debug) {
|
||||||
time = new Date();
|
time = new Date();
|
||||||
}
|
}
|
||||||
c.$table.addClass('hasFilters');
|
c.$table.addClass('hasFilters');
|
||||||
|
|
||||||
ts.filter.regex.child = new RegExp(c.cssChildRow);
|
$.extend( regex, {
|
||||||
ts.filter.regex.filtered = new RegExp(wo.filter_filteredRow);
|
child : new RegExp(c.cssChildRow),
|
||||||
|
filtered : new RegExp(wo.filter_filteredRow),
|
||||||
|
alreadyFiltered : new RegExp('(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i'),
|
||||||
|
toTest : new RegExp('\\s+(-|' + ts.language.to + ')\\s+', 'i'),
|
||||||
|
toSplit : new RegExp('(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi'),
|
||||||
|
andTest : new RegExp('\\s+(' + ts.language.and + '|&&)\\s+', 'i'),
|
||||||
|
andSplit : new RegExp('(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi'),
|
||||||
|
orReplace : new RegExp('\\s+(' + ts.language.or + ')\\s+', 'gi')
|
||||||
|
});
|
||||||
|
|
||||||
// don't build filter row if columnFilters is false or all columns are set to "filter-false" - issue #156
|
// don't build filter row if columnFilters is false or all columns are set to "filter-false" - issue #156
|
||||||
if (wo.filter_columnFilters !== false && c.$headers.filter('.filter-false').length !== c.$headers.length) {
|
if (wo.filter_columnFilters !== false && c.$headers.filter('.filter-false').length !== c.$headers.length) {
|
||||||
@ -578,6 +595,7 @@ ts.filter = {
|
|||||||
if (/(update|add)/.test(event.type) && event.type !== "updateComplete") {
|
if (/(update|add)/.test(event.type) && event.type !== "updateComplete") {
|
||||||
// force a new search since content has changed
|
// force a new search since content has changed
|
||||||
c.lastCombinedFilter = null;
|
c.lastCombinedFilter = null;
|
||||||
|
c.lastSearch = [];
|
||||||
}
|
}
|
||||||
// pass true (skipFirst) to prevent the tablesorter.setFilters function from skipping the first input
|
// pass true (skipFirst) to prevent the tablesorter.setFilters function from skipping the first input
|
||||||
// ensures all inputs are updated when a search is triggered on the table $('table').trigger('search', [...]);
|
// ensures all inputs are updated when a search is triggered on the table $('table').trigger('search', [...]);
|
||||||
@ -804,6 +822,7 @@ ts.filter = {
|
|||||||
} else if (filter === false) {
|
} else if (filter === false) {
|
||||||
// force filter refresh
|
// force filter refresh
|
||||||
c.lastCombinedFilter = null;
|
c.lastCombinedFilter = null;
|
||||||
|
c.lastSearch = [];
|
||||||
}
|
}
|
||||||
c.$table.trigger('filterStart', [filters]);
|
c.$table.trigger('filterStart', [filters]);
|
||||||
if (c.showProcessing) {
|
if (c.showProcessing) {
|
||||||
@ -858,8 +877,9 @@ ts.filter = {
|
|||||||
if (table.config.lastCombinedFilter === combinedFilters) { return; }
|
if (table.config.lastCombinedFilter === combinedFilters) { return; }
|
||||||
var cached, len, $rows, rowIndex, tbodyIndex, $tbody, $cells, columnIndex,
|
var cached, len, $rows, rowIndex, tbodyIndex, $tbody, $cells, columnIndex,
|
||||||
childRow, childRowText, exact, iExact, iFilter, lastSearch, matches, result,
|
childRow, childRowText, exact, iExact, iFilter, lastSearch, matches, result,
|
||||||
notFiltered, searchFiltered, filterMatched, showRow, time,
|
notFiltered, searchFiltered, filterMatched, showRow, time, val, indx,
|
||||||
anyMatch, iAnyMatch, rowArray, rowText, iRowText, rowCache,
|
anyMatch, iAnyMatch, rowArray, rowText, iRowText, rowCache,
|
||||||
|
regex = ts.filter.regex,
|
||||||
c = table.config,
|
c = table.config,
|
||||||
wo = c.widgetOptions,
|
wo = c.widgetOptions,
|
||||||
columns = c.columns,
|
columns = c.columns,
|
||||||
@ -889,18 +909,23 @@ ts.filter = {
|
|||||||
// optimize searching only through already filtered rows - see #313
|
// optimize searching only through already filtered rows - see #313
|
||||||
searchFiltered = true;
|
searchFiltered = true;
|
||||||
lastSearch = c.lastSearch || c.$table.data('lastSearch') || [];
|
lastSearch = c.lastSearch || c.$table.data('lastSearch') || [];
|
||||||
$.each(filters, function(indx, val) {
|
for (indx = 0; indx < columnIndex; indx++) {
|
||||||
|
val = filters[indx] || '';
|
||||||
|
// break out of loop if we've already determined not to search filtered rows
|
||||||
|
if (!searchFiltered) { indx = columnIndex; }
|
||||||
// search already filtered rows if...
|
// search already filtered rows if...
|
||||||
searchFiltered = searchFiltered &&
|
searchFiltered = searchFiltered && lastSearch.length &&
|
||||||
// there are changes from beginning of filter
|
// there are no changes from beginning of filter
|
||||||
(val || '').indexOf(lastSearch[indx]) === 0 &&
|
val.indexOf(lastSearch[indx] || '') === 0 &&
|
||||||
// if there is not a logical "or" in the string
|
// if there is NOT a logical "or", or range ("to" or "-") in the string
|
||||||
!/(\s+or\s+|\|)/g.test(val || '') &&
|
!regex.alreadyFiltered.test(val) &&
|
||||||
// if we are not doing exact matches
|
// if we are not doing exact matches, using "|" (logical or) or not "!"
|
||||||
!/[=\"]/.test(lastSearch[indx]) &&
|
!/[=\"\|!]/.test(val) &&
|
||||||
|
// don't search only filtered if the value is negative ('> -10' => '> -100' will ignore hidden rows)
|
||||||
|
!(/(>=?\s*-\d)/.test(val) || /(<=?\s*\d)/.test(val)) &&
|
||||||
// if filtering using a select without a "filter-match" class (exact match) - fixes #593
|
// if filtering using a select without a "filter-match" class (exact match) - fixes #593
|
||||||
!( val !== '' && wo.filter_functions && wo.filter_functions[indx] === true && !c.$headers.filter('[data-column="' + indx + '"]:last').hasClass('filter-match') );
|
!( val !== '' && wo.filter_functions && wo.filter_functions[indx] === true && !c.$headers.filter('[data-column="' + indx + '"]:last').hasClass('filter-match') );
|
||||||
});
|
}
|
||||||
notFiltered = $rows.not('.' + wo.filter_filteredRow).length;
|
notFiltered = $rows.not('.' + wo.filter_filteredRow).length;
|
||||||
// can't search when all rows are hidden - this happens when looking for exact matches
|
// can't search when all rows are hidden - this happens when looking for exact matches
|
||||||
if (searchFiltered && notFiltered === 0) { searchFiltered = false; }
|
if (searchFiltered && notFiltered === 0) { searchFiltered = false; }
|
||||||
@ -919,7 +944,7 @@ ts.filter = {
|
|||||||
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
||||||
childRow = $rows[rowIndex].className;
|
childRow = $rows[rowIndex].className;
|
||||||
// skip child rows & already filtered rows
|
// skip child rows & already filtered rows
|
||||||
if ( ts.filter.regex.child.test(childRow) || (searchFiltered && ts.filter.regex.filtered.test(childRow)) ) { continue; }
|
if ( regex.child.test(childRow) || (searchFiltered && regex.filtered.test(childRow)) ) { continue; }
|
||||||
showRow = true;
|
showRow = true;
|
||||||
// *** nextAll/nextUntil not supported by Zepto! ***
|
// *** nextAll/nextUntil not supported by Zepto! ***
|
||||||
childRow = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
|
childRow = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
|
||||||
@ -975,7 +1000,7 @@ ts.filter = {
|
|||||||
exact = $.trim($cells.eq(columnIndex).text());
|
exact = $.trim($cells.eq(columnIndex).text());
|
||||||
exact = c.sortLocaleCompare ? ts.replaceAccents(exact) : exact; // issue #405
|
exact = c.sortLocaleCompare ? ts.replaceAccents(exact) : exact; // issue #405
|
||||||
}
|
}
|
||||||
iExact = !ts.filter.regex.type.test(typeof exact) && wo.filter_ignoreCase ? exact.toLocaleLowerCase() : exact;
|
iExact = !regex.type.test(typeof exact) && wo.filter_ignoreCase ? exact.toLocaleLowerCase() : exact;
|
||||||
result = showRow; // if showRow is true, show that row
|
result = showRow; // if showRow is true, show that row
|
||||||
|
|
||||||
// replace accents - see #357
|
// replace accents - see #357
|
||||||
@ -1246,6 +1271,7 @@ ts.setFilters = function(table, filter, apply, skipFirst) {
|
|||||||
if (c && apply) {
|
if (c && apply) {
|
||||||
// ensure new set filters are applied, even if the search is the same
|
// ensure new set filters are applied, even if the search is the same
|
||||||
c.lastCombinedFilter = null;
|
c.lastCombinedFilter = null;
|
||||||
|
c.lastSearch = [];
|
||||||
ts.filter.searching(c.$table[0], filter, skipFirst);
|
ts.filter.searching(c.$table[0], filter, skipFirst);
|
||||||
c.$table.trigger('filterFomatterUpdate');
|
c.$table.trigger('filterFomatterUpdate');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user