Filter: add data parameter to filter_functions. See #891

This commit is contained in:
Mottie 2015-05-05 23:44:06 -05:00
parent a327084b16
commit b591583669
14 changed files with 389 additions and 279 deletions

View File

@ -1,4 +1,4 @@
/*! tablesorter (FORK) - updated 04-30-2015 (v2.21.5)*/
/*! tablesorter (FORK) - updated 05-05-2015 (v2.21.5)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -245,6 +245,29 @@
return ts.getParserById('text');
}
// centralized function to extract/parse cell contents
function getParsedText( c, cell, colIndex, txt ) {
var val = '',
parser = c.parsers[ colIndex ],
extractor = c.extractors[ colIndex ];
txt = txt || ts.getElementText( c, cell, colIndex );
if ( parser ) {
// do extract before parsing if there is one
if ( extractor && typeof extractor.format === 'function' ) {
txt = extractor.format( txt, c.table, cell, colIndex );
}
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
val = parser.id === 'no-parser' ? '' :
// make sure txt is a string (extractor may have converted it)
parser.format( '' + txt, c.table, cell, colIndex );
if ( c.ignoreCase && typeof val === 'string' ) {
val = val.toLowerCase();
}
}
return val;
}
function buildParserCache(table) {
var c = table.config,
// update table bodies in case we start with an empty table
@ -308,11 +331,10 @@
/* utils */
function buildCache(table) {
var cc, t, tx, v, i, j, k, $row, cols, cacheTime,
var cc, t, v, i, j, k, $row, cols, cacheTime,
totalRows, rowData, colMax,
c = table.config,
$tb = c.$tbodies,
extractors = c.extractors,
parsers = c.parsers;
c.cache = {};
c.totalRows = 0;
@ -361,7 +383,7 @@
}
rowData.$row = $row;
rowData.order = i; // add original row position to rowCache
for (j = 0; j < c.columns; ++j) {
for ( j = 0; j < c.columns; ++j ) {
if (typeof parsers[j] === 'undefined') {
if (c.debug) {
log('No parser found for cell:', $row[0].cells[j], 'does it have a header?');
@ -370,24 +392,16 @@
}
t = ts.getElementText(c, $row[0].cells[j], j);
rowData.raw.push(t); // save original row text
// do extract before parsing if there is one
if (typeof extractors[j].id === 'undefined') {
tx = t;
} else {
tx = extractors[j].format(t, table, $row[0].cells[j], j);
}
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(tx, table, $row[0].cells[j], j);
cols.push( c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v );
if ((parsers[j].type || '').toLowerCase() === 'numeric') {
v = getParsedText( c, $row[ 0 ].cells[ j ], j, t );
cols.push( v );
if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
// determine column max value (ignore sign)
colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0);
colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 );
}
}
// ensure rowData is always in the same location (after the last column)
cols[c.columns] = rowData;
cc.normalized.push(cols);
cols[ c.columns ] = rowData;
cc.normalized.push( cols );
}
cc.colMax = colMax;
// total up rows, not including child rows
@ -911,35 +925,31 @@
table.isUpdating = true;
$table.find(c.selectorRemove).remove();
// get position from the dom
var v, t, row, icell,
var t, row, icell, cache,
$tb = c.$tbodies,
$cell = $(cell),
// update cache - format: function(s, table, cell, cellIndex)
// no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
tbcache = c.cache[ tbdy ],
$row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
cell = $cell[0]; // in case cell is a jQuery object
// tbody may not exist if update is initialized while tbody is removed for processing
if ($tb.length && tbdy >= 0) {
row = $tb.eq(tbdy).find('tr').index( $row );
row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
cache = tbcache.normalized[ row ];
icell = $cell.index();
c.cache[tbdy].normalized[row][c.columns].$row = $row;
if (typeof c.extractors[icell].id === 'undefined') {
t = ts.getElementText(c, cell, icell);
} else {
t = c.extractors[icell].format( ts.getElementText(c, cell, icell), table, cell, icell );
}
v = c.parsers[icell].id === 'no-parser' ? '' :
c.parsers[icell].format( t, table, cell, icell );
c.cache[tbdy].normalized[row][icell] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
if ((c.parsers[icell].type || '').toLowerCase() === 'numeric') {
t = getParsedText( c, cell, icell );
cache[ icell ] = t;
cache[ c.columns ].$row = $row;
if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
// update column max value (ignore sign)
c.cache[tbdy].colMax[icell] = Math.max(Math.abs(v) || 0, c.cache[tbdy].colMax[icell] || 0);
tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0);
}
v = resort !== 'undefined' ? resort : c.resort;
if (v !== false) {
t = resort !== 'undefined' ? resort : c.resort;
if (t !== false) {
// widgets will be reapplied
checkResort(c, v, callback);
checkResort(c, t, callback);
} else {
// don't reapply widgets is resort is false, just in case it causes
// problems with element focus
@ -959,7 +969,7 @@
commonUpdate(table, resort, callback);
} else {
$row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
var i, j, l, t, v, rowData, cells,
var i, j, l, rowData, cells,
rows = $row.filter('tr').length,
tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
// fixes adding rows to an empty table - see issue #179
@ -977,14 +987,7 @@
};
// add each cell
for (j = 0; j < l; j++) {
if (typeof c.extractors[j].id === 'undefined') {
t = ts.getElementText(c, $row[i].cells[j], j);
} else {
t = c.extractors[j].format( ts.getElementText(c, $row[i].cells[j], j), table, $row[i].cells[j], j );
}
v = c.parsers[j].id === 'no-parser' ? '' :
c.parsers[j].format( t, table, $row[i].cells[j], j );
cells[j] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
cells[j] = getParsedText( c, $row[i].cells[j], j );
if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
// update column max value (ignore sign)
c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
@ -2608,11 +2611,19 @@ ts.filter = {
types: {
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test(data.iFilter) ) {
if ( ts.filter.regex.regex.test(data.filter) ) {
var matches,
regex = ts.filter.regex.regex.exec(data.iFilter);
wo = c.widgetOptions,
// cache regex per column for optimal speed
regex = wo.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
matches = new RegExp(regex[1], regex[2]).test( data.iExact );
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] );
}
matches = regex.test( data.exact );
} catch (error) {
matches = false;
}
@ -2771,6 +2782,7 @@ 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*=","]';
@ -3296,7 +3308,7 @@ ts.filter = {
},
findRows: function(table, filters, combinedFilters) {
if (table.config.lastCombinedFilter === combinedFilters || !table.config.widgetOptions.filter_initialized) { return; }
var len, norm_rows, $rows, rowIndex, tbodyIndex, $tbody, $cells, $cell, columnIndex,
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,
@ -3304,10 +3316,13 @@ ts.filter = {
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
data = { anyMatch: false },
data = { anyMatch: false, filters: filters },
// 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 ||
@ -3429,30 +3444,32 @@ ts.filter = {
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;
// 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 = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
childRow = data.$row.nextUntil('tr:not(.' + c.cssChildRow + ')');
// 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;
$cells = $rows.eq(rowIndex).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 = $cells.map(function(i){
data.rowArray = data.$cells.map(function(i){
if ( $.inArray(i, columnIndex) > -1 ) {
var txt;
if (data.parsed[i]) {
txt = data.cacheArray[i];
} else {
txt = this ? this.getAttribute( c.textAttribute ) || this.textContent || $(this).text() : '';
txt = data.rawArray[i];
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
if (c.sortLocaleCompare) {
txt = ts.replaceAccents(txt);
@ -3507,8 +3524,7 @@ ts.filter = {
if (wo.filter_useParsedData || data.parsed[columnIndex]) {
data.exact = data.cache;
} else {
val = $cells[columnIndex];
result = val ? $.trim( val.getAttribute( c.textAttribute ) || val.textContent || $cells.eq(columnIndex).text() ) : '';
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;
@ -3540,10 +3556,10 @@ ts.filter = {
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, $rows.eq(rowIndex), c);
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, $rows.eq(rowIndex), c);
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
}
}
if (filterMatched === null) {
@ -3571,7 +3587,7 @@ ts.filter = {
showRow = (result) ? showRow : false;
}
}
$rows.eq(rowIndex)
data.$row
.toggleClass(wo.filter_filteredRow, !showRow)[0]
.display = showRow ? '' : 'none';
if (childRow.length) {
@ -3695,10 +3711,8 @@ ts.filter = {
if (wo.filter_useParsedData || c.parsers[column].parsed || c.$headerIndexed[column].hasClass('filter-parsed')) {
arry.push( '' + cache.normalized[rowIndex][column] );
} else {
cell = row.cells[column];
if (cell) {
arry.push( $.trim( cell.getAttribute( c.textAttribute ) || cell.textContent || $(cell).text() ) );
}
// get raw cached data instead of content directly from the cells
arry.push( cache.normalized[rowIndex][c.columns].raw[column] );
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -243,6 +243,29 @@
return ts.getParserById('text');
}
// centralized function to extract/parse cell contents
function getParsedText( c, cell, colIndex, txt ) {
var val = '',
parser = c.parsers[ colIndex ],
extractor = c.extractors[ colIndex ];
txt = txt || ts.getElementText( c, cell, colIndex );
if ( parser ) {
// do extract before parsing if there is one
if ( extractor && typeof extractor.format === 'function' ) {
txt = extractor.format( txt, c.table, cell, colIndex );
}
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
val = parser.id === 'no-parser' ? '' :
// make sure txt is a string (extractor may have converted it)
parser.format( '' + txt, c.table, cell, colIndex );
if ( c.ignoreCase && typeof val === 'string' ) {
val = val.toLowerCase();
}
}
return val;
}
function buildParserCache(table) {
var c = table.config,
// update table bodies in case we start with an empty table
@ -306,11 +329,10 @@
/* utils */
function buildCache(table) {
var cc, t, tx, v, i, j, k, $row, cols, cacheTime,
var cc, t, v, i, j, k, $row, cols, cacheTime,
totalRows, rowData, colMax,
c = table.config,
$tb = c.$tbodies,
extractors = c.extractors,
parsers = c.parsers;
c.cache = {};
c.totalRows = 0;
@ -359,7 +381,7 @@
}
rowData.$row = $row;
rowData.order = i; // add original row position to rowCache
for (j = 0; j < c.columns; ++j) {
for ( j = 0; j < c.columns; ++j ) {
if (typeof parsers[j] === 'undefined') {
if (c.debug) {
log('No parser found for cell:', $row[0].cells[j], 'does it have a header?');
@ -368,24 +390,16 @@
}
t = ts.getElementText(c, $row[0].cells[j], j);
rowData.raw.push(t); // save original row text
// do extract before parsing if there is one
if (typeof extractors[j].id === 'undefined') {
tx = t;
} else {
tx = extractors[j].format(t, table, $row[0].cells[j], j);
}
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(tx, table, $row[0].cells[j], j);
cols.push( c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v );
if ((parsers[j].type || '').toLowerCase() === 'numeric') {
v = getParsedText( c, $row[ 0 ].cells[ j ], j, t );
cols.push( v );
if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
// determine column max value (ignore sign)
colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0);
colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 );
}
}
// ensure rowData is always in the same location (after the last column)
cols[c.columns] = rowData;
cc.normalized.push(cols);
cols[ c.columns ] = rowData;
cc.normalized.push( cols );
}
cc.colMax = colMax;
// total up rows, not including child rows
@ -909,35 +923,31 @@
table.isUpdating = true;
$table.find(c.selectorRemove).remove();
// get position from the dom
var v, t, row, icell,
var t, row, icell, cache,
$tb = c.$tbodies,
$cell = $(cell),
// update cache - format: function(s, table, cell, cellIndex)
// no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
tbcache = c.cache[ tbdy ],
$row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
cell = $cell[0]; // in case cell is a jQuery object
// tbody may not exist if update is initialized while tbody is removed for processing
if ($tb.length && tbdy >= 0) {
row = $tb.eq(tbdy).find('tr').index( $row );
row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
cache = tbcache.normalized[ row ];
icell = $cell.index();
c.cache[tbdy].normalized[row][c.columns].$row = $row;
if (typeof c.extractors[icell].id === 'undefined') {
t = ts.getElementText(c, cell, icell);
} else {
t = c.extractors[icell].format( ts.getElementText(c, cell, icell), table, cell, icell );
}
v = c.parsers[icell].id === 'no-parser' ? '' :
c.parsers[icell].format( t, table, cell, icell );
c.cache[tbdy].normalized[row][icell] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
if ((c.parsers[icell].type || '').toLowerCase() === 'numeric') {
t = getParsedText( c, cell, icell );
cache[ icell ] = t;
cache[ c.columns ].$row = $row;
if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
// update column max value (ignore sign)
c.cache[tbdy].colMax[icell] = Math.max(Math.abs(v) || 0, c.cache[tbdy].colMax[icell] || 0);
tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0);
}
v = resort !== 'undefined' ? resort : c.resort;
if (v !== false) {
t = resort !== 'undefined' ? resort : c.resort;
if (t !== false) {
// widgets will be reapplied
checkResort(c, v, callback);
checkResort(c, t, callback);
} else {
// don't reapply widgets is resort is false, just in case it causes
// problems with element focus
@ -957,7 +967,7 @@
commonUpdate(table, resort, callback);
} else {
$row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
var i, j, l, t, v, rowData, cells,
var i, j, l, rowData, cells,
rows = $row.filter('tr').length,
tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
// fixes adding rows to an empty table - see issue #179
@ -975,14 +985,7 @@
};
// add each cell
for (j = 0; j < l; j++) {
if (typeof c.extractors[j].id === 'undefined') {
t = ts.getElementText(c, $row[i].cells[j], j);
} else {
t = c.extractors[j].format( ts.getElementText(c, $row[i].cells[j], j), table, $row[i].cells[j], j );
}
v = c.parsers[j].id === 'no-parser' ? '' :
c.parsers[j].format( t, table, $row[i].cells[j], j );
cells[j] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
cells[j] = getParsedText( c, $row[i].cells[j], j );
if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
// update column max value (ignore sign)
c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
/*! tablesorter (FORK) - updated 04-16-2015 (v2.21.5)*/
/*! tablesorter (FORK) - updated 05-05-2015 (v2.21.5)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -466,11 +466,19 @@ ts.filter = {
types: {
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test(data.iFilter) ) {
if ( ts.filter.regex.regex.test(data.filter) ) {
var matches,
regex = ts.filter.regex.regex.exec(data.iFilter);
wo = c.widgetOptions,
// cache regex per column for optimal speed
regex = wo.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
matches = new RegExp(regex[1], regex[2]).test( data.iExact );
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] );
}
matches = regex.test( data.exact );
} catch (error) {
matches = false;
}
@ -629,6 +637,7 @@ 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*=","]';
@ -1154,7 +1163,7 @@ ts.filter = {
},
findRows: function(table, filters, combinedFilters) {
if (table.config.lastCombinedFilter === combinedFilters || !table.config.widgetOptions.filter_initialized) { return; }
var len, norm_rows, $rows, rowIndex, tbodyIndex, $tbody, $cells, $cell, columnIndex,
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,
@ -1162,10 +1171,13 @@ ts.filter = {
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
data = { anyMatch: false },
data = { anyMatch: false, filters: filters },
// 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 ||
@ -1287,30 +1299,32 @@ ts.filter = {
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;
// 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 = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
childRow = data.$row.nextUntil('tr:not(.' + c.cssChildRow + ')');
// 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;
$cells = $rows.eq(rowIndex).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 = $cells.map(function(i){
data.rowArray = data.$cells.map(function(i){
if ( $.inArray(i, columnIndex) > -1 ) {
var txt;
if (data.parsed[i]) {
txt = data.cacheArray[i];
} else {
txt = this ? this.getAttribute( c.textAttribute ) || this.textContent || $(this).text() : '';
txt = data.rawArray[i];
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
if (c.sortLocaleCompare) {
txt = ts.replaceAccents(txt);
@ -1365,8 +1379,7 @@ ts.filter = {
if (wo.filter_useParsedData || data.parsed[columnIndex]) {
data.exact = data.cache;
} else {
val = $cells[columnIndex];
result = val ? $.trim( val.getAttribute( c.textAttribute ) || val.textContent || $cells.eq(columnIndex).text() ) : '';
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;
@ -1398,10 +1411,10 @@ ts.filter = {
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, $rows.eq(rowIndex), c);
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, $rows.eq(rowIndex), c);
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
}
}
if (filterMatched === null) {
@ -1429,7 +1442,7 @@ ts.filter = {
showRow = (result) ? showRow : false;
}
}
$rows.eq(rowIndex)
data.$row
.toggleClass(wo.filter_filteredRow, !showRow)[0]
.display = showRow ? '' : 'none';
if (childRow.length) {
@ -1553,10 +1566,8 @@ ts.filter = {
if (wo.filter_useParsedData || c.parsers[column].parsed || c.$headerIndexed[column].hasClass('filter-parsed')) {
arry.push( '' + cache.normalized[rowIndex][column] );
} else {
cell = row.cells[column];
if (cell) {
arry.push( $.trim( cell.getAttribute( c.textAttribute ) || cell.textContent || $(cell).text() ) );
}
// get raw cached data instead of content directly from the cells
arry.push( cache.normalized[rowIndex][c.columns].raw[column] );
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -100,6 +100,7 @@ $(function() {
<h3><a href="#">Notes</a></h3>
<div>
<ul>
<li>In <span class="version">v2.21.6</span>, additional values were added to the <code>data</code> parameter as it is now provided as a parameter to all <a href="index.html#widget-filter-functions"><code>filter_functions</code></a>. See the "How to add Custom filter types" section below to review the new additions.</li>
<li><span class="label warning">Notice!</span> In version <span class="version">v2.17.8</span>, some drastic changes were made to the way variables are passed to the filters. Please check out the "How to add Custom Filter types" section below.</li>
<li>This demo was added in <span class="version">v2.17.5</span>, but modification using these instructions works for v2.13.3+; when the filter widget was restructured to allow the adding of custom filter search types.</li>
<li>In this demo, two additional search types have been added as an example
@ -151,8 +152,12 @@ $(function() {
<li>Within your filter, first test for your designator symbol.
<ul>
<li>If it exists within the filter, then do your comparison and return a boolean of <code>true</code> or <code>false</code>.</li>
<li>The following arguments are passed to the filter function within the <code>data</code> parameter (changed in <span class="version updated">v2.17.8</span>):
<li>The following arguments are passed within the <code>data</code> parameter to both the <code>filter_function</code> &amp; filter type function (changed in <span class="version updated">v2.21.6</span>):
<ul>
<li><code>data.$row</code> - The jQuery object of the current row being processed by the filter widget; added <span class="version">v2.21.6</span>.</li>
<li><code>data.$cells</code> - A jQuery object containing all the table cells in the current row being processed; added <span class="version">v2.21.6</span>.</li>
<li><code>data.filters</code> - Array of filters for all columns (some array values may be undefined); added <span class="version">v2.21.6</span>.<br><br></li>
<li><code>data.filter</code> - The exact text from the filter input (e.g. <code>^h</code>).</li>
<li><code>data.iFilter</code> - The text from the filter in all lower case for case insensitive searches, if <code>table.config.widgetOptions.filter_ignoreCase</code> is <code>true</code>.</li>
<li><code>data.exact</code> - The exact (or parsed) text from the current table cell, or the entire row if <code>data.anyMatch</code> is <code>true</code>; the parsed text is passed when the column has a <code>"filter-parsed"</code> class name set.</li>
@ -162,12 +167,12 @@ $(function() {
<li><code>data.anyMatch</code> - This is a boolean value indicating when the <code>data.exact</code> and <code>data.iExact</code> parameters contain data from the entire row instead of one cell. This value will always be <code>false</code> if the table does not include an associated any match filter.<br><br></li>
<li><code>data.rowArray</code> - An array of the exact text from each table cell.</li>
<li><code>data.cacheArray</code> - An array of parsed text from each table cell.</li>
<li><code>data.childRowText</code> - contains all text from any associated child rows.</li>
<li><code>data.rawArray</code> - An array of raw content extracted from each table cell in the row being processed; added <span class="version">v2.21.6</span>.</li>
<li><code>data.rowArray</code> - An array of the modified exact text from each table cell in the current row being processed. The content will be in all lower case, if the <a href="index.html#ignorecase"><code>table.config.ignoreCase</code> option</a> is <code>true</code> &amp; accents replaced if the <a href="index.html#sortlocalecompare"><code>table.config.sortLocaleCompare</code> option</a> is <code>true</code>).</li>
<li><code>data.cacheArray</code> - An array of parsed content from each table cell in the row being processed.</li>
<li><code>data.childRowText</code> - contains <em>all</em> text from any associated child rows.</li>
<li><code>data.parsed</code> - An array of boolean flags that indicate if the column data should obtained from parsed values, or not; obtained from <code>filter_useParsedData</code> setting or <code>filter-parsed</code> classes on the header cells.<br>
<span class="label label-info">Note</span> Be aware that the values in this array will all be in lower case if the <code>table.config.ignoreCase</code> option is <code>true</code>.
<li><code>data.parsed</code> - An array of boolean flags that indicate if the column data should be obtained from parsed values, or not; obtained from <code>filter_useParsedData</code> setting or <code>filter-parsed</code> classes on the header cells.
</li>
</ul>
<br>

View File

@ -43,6 +43,24 @@
return false;
});
$('.accordion button[data-filter-column]').click(function(){
var filters = [],
$t = $(this),
col = $t.data('filter-column'), // zero-based index
txt = $t.data('filter-text') || $t.text(); // text to add to filter
filters[col] = txt;
$.tablesorter.setFilters( $('#demo table'), filters, true );
return false;
});
$('button.search-type').click(function(){
var c = $('#demo table')[0].config,
wo = c.widgetOptions,
search = wo.filter_searchFiltered = !wo.filter_searchFiltered;
$('#search-type').html( '' + search );
$.tablesorter.setFilters( c.$table, [ '', 'Evan' ], true );
});
});
</script>
@ -109,28 +127,28 @@
// '.first-name' : true,
// Exact match only
1 : function(e, n, f, i, $r, c) {
1 : function(e, n, f, i, $r, c, data) {
return e === f;
},
// Add these options to the select dropdown (regex example)
2 : {
"A - D" : function(e, n, f, i, $r, c) { return /^[A-D]/.test(e); },
"E - H" : function(e, n, f, i, $r, c) { return /^[E-H]/.test(e); },
"I - L" : function(e, n, f, i, $r, c) { return /^[I-L]/.test(e); },
"M - P" : function(e, n, f, i, $r, c) { return /^[M-P]/.test(e); },
"Q - T" : function(e, n, f, i, $r, c) { return /^[Q-T]/.test(e); },
"U - X" : function(e, n, f, i, $r, c) { return /^[U-X]/.test(e); },
"Y - Z" : function(e, n, f, i, $r, c) { return /^[Y-Z]/.test(e); }
"A - D" : function(e, n, f, i, $r, c, data) { return /^[A-D]/.test(e); },
"E - H" : function(e, n, f, i, $r, c, data) { return /^[E-H]/.test(e); },
"I - L" : function(e, n, f, i, $r, c, data) { return /^[I-L]/.test(e); },
"M - P" : function(e, n, f, i, $r, c, data) { return /^[M-P]/.test(e); },
"Q - T" : function(e, n, f, i, $r, c, data) { return /^[Q-T]/.test(e); },
"U - X" : function(e, n, f, i, $r, c, data) { return /^[U-X]/.test(e); },
"Y - Z" : function(e, n, f, i, $r, c, data) { return /^[Y-Z]/.test(e); }
},
// Add these options to the select dropdown (numerical comparison example)
// Note that only the normalized (n) value will contain numerical data
// If you use the exact text, you'll need to parse it (parseFloat or parseInt)
4 : {
"< $10" : function(e, n, f, i, $r, c) { return n < 10; },
"$10 - $100" : function(e, n, f, i, $r, c) { return n >= 10 && n <=100; },
"> $100" : function(e, n, f, i, $r, c) { return n > 100; }
"< $10" : function(e, n, f, i, $r, c, data) { return n < 10; },
"$10 - $100" : function(e, n, f, i, $r, c, data) { return n >= 10 && n <=100; },
"> $100" : function(e, n, f, i, $r, c, data) { return n > 100; }
}
}
@ -157,6 +175,16 @@
<h3><a href="#">Notes</a></h3>
<div>
<ul>
<li>In <span class="version">v2.21.6</span>,
<ul>
<li>An additional <code>data</code> parameter was added to the filter functions. It is an object which contains all data provided to the filter type functions (see <a href="example-widget-filter-custom-search.html#how_to_add_custom_filter_types">all the data values here</a>).</li>
<li><span class="label warning">*WARNING*</span> In a future update, the filter function parameters will change to clean up the code (I know, it's messy)!
<pre class="prettyprint lang-js">filter_functions : {
// function(e, n, f, i, $r, c, data) {} <- current parameters
0 : function(c, data) {} // planned change (version undetermined)
}</pre>The <code>e</code> (exact table cell text), <code>n</code> (normalized table cell text), <code>f</code> (filter input value), <code>i</code> (column index) and <code>$r</code> (current row; jQuery object) are all already included in the <code>data</code> object.<p></p></li>
</ul>
</li>
<li>In <span class="version">v2.21.0</span>, the filter functions provide an additional parameter <code>c</code> which is the <code>table.config</code>.</li>
<li>In <span class="version updated">v2.17.0</span>, the <code>filter_functions</code> column can also be referenced by using a jQuery selector (e.g. class name or ID).</li>
<li>In <span class="version">v2.16.3</span>,
@ -203,14 +231,15 @@
<li>To enable this type of filter, add your custom function to the <code>filter_functions</code> option following this example:<pre class="prettyprint lang-javascript">filter_functions : {
// Exact match only
1 : function(e, n, f, i, $r, c) {
1 : function(e, n, f, i, $r, c, data) {
return e === f;
}
}</pre></li>
<li>The example shows you how to show only exact matches. The problem with this is that you can't see the matches while typing unless you set the <code>filter_searchDelay</code> option to be a bit longer.</li>
<li>Also, the example only checks for an exact match (<code>===</code>) meaning the <code>filter_ignoreCase</code> option is ignored, but other comparisons can be made using regex and the insensitive &quot;i&quot; flag.</li>
<li>See the filter function information below.</li>
<li><span class="label warning">*NOTE*</span> If using an exact match function like this, consider setting the <a href="index.html#widget-filter-searchfiltered"><code>filter_searchFiltered</code></a> option to false. If it were set to <code>true</code>, the filter widget wouldn't know to search through the entire contents of the column if the content were only slightly different. To see this problem, search for <button data-filter-column="1">Evan</button> in the "Last Name" column, then add an "s" to the end to find "Evans". No results will show up, unless the search filtered option is <code>false</code>.</li>
<li>See the filter function information below for more details about the function parameters.</li>
</ul>
</div>
@ -223,13 +252,13 @@
// Add these options to the select dropdown (regex example)
2 : {
&quot;A - D&quot; : function(e, n, f, i, $r, c) { return /^[A-D]/.test(e); },
&quot;E - H&quot; : function(e, n, f, i, $r, c) { return /^[E-H]/.test(e); },
&quot;I - L&quot; : function(e, n, f, i, $r, c) { return /^[I-L]/.test(e); },
&quot;M - P&quot; : function(e, n, f, i, $r, c) { return /^[M-P]/.test(e); },
&quot;Q - T&quot; : function(e, n, f, i, $r, c) { return /^[Q-T]/.test(e); },
&quot;U - X&quot; : function(e, n, f, i, $r, c) { return /^[U-X]/.test(e); },
&quot;Y - Z&quot; : function(e, n, f, i, $r, c) { return /^[Y-Z]/.test(e); }
&quot;A - D&quot; : function(e, n, f, i, $r, c, data) { return /^[A-D]/.test(e); },
&quot;E - H&quot; : function(e, n, f, i, $r, c, data) { return /^[E-H]/.test(e); },
&quot;I - L&quot; : function(e, n, f, i, $r, c, data) { return /^[I-L]/.test(e); },
&quot;M - P&quot; : function(e, n, f, i, $r, c, data) { return /^[M-P]/.test(e); },
&quot;Q - T&quot; : function(e, n, f, i, $r, c, data) { return /^[Q-T]/.test(e); },
&quot;U - X&quot; : function(e, n, f, i, $r, c, data) { return /^[U-X]/.test(e); },
&quot;Y - Z&quot; : function(e, n, f, i, $r, c, data) { return /^[Y-Z]/.test(e); }
}
}</pre></li>
@ -238,12 +267,12 @@
// Note that only the normalized (n) value will contain numerical data
// If you use the exact text, you'll need to parse it (parseFloat or parseInt)
4 : {
&quot;&lt; $10&quot; : function(e, n, f, i, $r, c) { return n &lt; 10; },
&quot;$10 - $100&quot; : function(e, n, f, i, $r, c) { return n &gt;= 10 && n &lt;=100; },
&quot;&gt; $100&quot; : function(e, n, f, i, $r, c) { return n &gt; 100; }
&quot;&lt; $10&quot; : function(e, n, f, i, $r, c, data) { return n &lt; 10; },
&quot;$10 - $100&quot; : function(e, n, f, i, $r, c, data) { return n &gt;= 10 && n &lt;=100; },
&quot;&gt; $100&quot; : function(e, n, f, i, $r, c, data) { return n &gt; 100; }
}
}</pre></li>
<li>See the &quot;Filter function information&quot; section below.</li>
<li>See the &quot;Filter function information&quot; section below for more details about the function parameters.</li>
</ul>
</div>
@ -268,7 +297,7 @@
<div>
<ul>
<li>The custom function must return a boolean value. If <code>true</code> is returned, the row will be shown if all other filters match; and if <code>false</code> is returned, the row will be hidden.
<pre class="prettyprint lang-javascript">function(e, n, f, i, $r, c) { return test; /* test should be a Boolean (true or false) */ }</pre>
<pre class="prettyprint lang-javascript">function(e, n, f, i, $r, c, data) { return test; /* test should be a Boolean (true or false) */ }</pre>
</li>
<li>The <strong>exact text (e)</strong> of the table cell is a variable passed to the function. Note that numbers will need to be parsed to make comparisons.</li>
<li><strong>Normalized table cell data (n)</strong> is the next varibale passed to the function.
@ -288,13 +317,16 @@
<li><span class="label alert">* NOTE *</span> The row object provided is <em>not</em> attached to the table, so using something like <code>.parent()</code> or <code>.closest()</code> will not work!</li>
<li>For this reason, the next parameter (<code>c</code>) was added.</li>
</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>
</ul>
</div>
</div>
<h1>Demo</h1>
<button type="button" class="match" data-filter-column="0" data-filter-text="Denni">Match</button> <span id="mode">false</span> (toggle &quot;filter-match&quot; class on First Name column)<br>
<button type="button" class="match" data-filter-column="0" data-filter-text="Denni">Toggle</button> <span id="mode" class="bright">false</span> &quot;filter-match&quot; class name on the "First Name" column<br>
<button type="button" class="search-type">Toggle</button> filter_searchFiltered : <span id="search-type" class="bright">true</span> (if true, the search is performed on already filtered rows, with some exceptions)<br>
<button type="button" class="reset">Reset Search</button>
<div id="demo"><table class="tablesorter">

View File

@ -545,13 +545,24 @@ $(function(){
<pre class="prettyprint lang-javascript">$('.tablesorter th:eq(0)').data('placeholder', 'Search for...')</pre>
</blockquote>
<h3>Set Filter Initial Searches</h3>
<blockquote>
Set a <code>data-value</code> attribute (data-attribute name set by the <code>filter_defaultAttrib</code> option) on the associated table header with the desired initial search value.
<pre class="prettyprint lang-html">&lt;th data-value=&quot;&lt;=100&quot;&gt;Price&lt;/th&gt;</pre>
or, set the header cell's jQuery data
<pre class="prettyprint lang-javascript">$('.tablesorter th:eq(0)').data('value', '&lt;=100')</pre>
</blockquote>
<h3>filterReset</h3>
<blockquote>
Use the <code>filterReset</code> method to reset (clear) all of the current filters using this method
<pre class="prettyprint lang-javascript">$('table').trigger('filterReset');</pre>
or, just add an element to your page and point to it by setting the <code>filter_reset</code> option, to allow user interaction.
<p></p>
<span class="label label-info">*NOTE*</span> delegated event bindings are used so these "reset" elements can be dynamically added and removed from the document.
</blockquote>
<h3>search</h3>
<h3>Search</h3>
<blockquote>
With this method, you can pass an array of filter values:
<pre class="prettyprint lang-javascript">// apply &quot;2?%&quot; filter to the fifth column (zero-based index)
@ -598,7 +609,7 @@ $.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '2?%' ], true );</pr
$.tablesorter.setFilters( $('table'), [ '', '', '', '', '', '', '11' ], true );</pre>
</blockquote>
<h3>Bind External filter</h3>
<h3>Bind external filter</h3>
<blockquote>
Use this method to bind external search filters
<ul>

View File

@ -481,13 +481,13 @@
<li><a href="example-widget-column-selector.html">Column Selector widget</a> (<span class="version">v2.15</span>; <span class="version updated">v2.21.0</span>).</li>
<li><a href="example-widget-editable.html">Content Editable widget</a> (v2.9; <span class="version updated">v2.19.1</span>).</li>
<li><span class="label label-info">Beta</span> <a href="example-dragtable.html">Dragtable mod</a> - (jQuery UI widget for column reordering [<a href="http://stackoverflow.com/a/27770224/145346">ref</a>]; <span class="version">v2.19.0</span>).</li>
<li><span class="results">&dagger;</span> Filter Widget (<span class="version updated">v2.21.5</span>):
<li><span class="results">&dagger;</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-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-search.html">custom searches</a> (<span class="version">v2.17.5</span>; <span class="version updated">v2.17.8</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>
<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>
@ -2543,10 +2543,17 @@ $(function(){
Filter widget: Customize the filter widget by adding a select dropdown with content, custom options or custom filter functions (v2.3.6; <span class="version updated">v2.17.0</span>).
<div class="collapsible">
<br>
In <span class="version updated">v2.21.6</span>, a <code>data</code> parameter was added to that long list of parameters.<p></p>
<span class="label alert">*WARNING*</span> In a future update, the filter function parameters will be cleaned up and changed as follows!
<pre class="prettyprint lang-js">filter_functions : {
// function(e, n, f, i, $r, c, data) {} <- current parameters
0 : function(c, data) {} // planned change (version undetermined)
}</pre>The <code>e</code> (exact table cell text), <code>n</code> (normalized table cell text), <code>f</code> (filter input value), <code>i</code> (column index) and <code>$r</code> (current row; jQuery object) are all already included in the <a href="example-widget-filter-custom-search.html#how_to_add_custom_filter_types"><code>data</code></a> object.
<p></p>
In <span class="version updated">v2.17.0</span>, the <code>filter_functions</code> column can also be referenced by using a jQuery selector (e.g. class name or ID) that points to a table <em>header</em> cell.<br>
<pre class="prettyprint lang-js">filter_functions : {
".col-date" : {
"&lt; 2004" : function (e, n, f, i, $r, c) {
"&lt; 2004" : function (e, n, f, i, $r, c, data) {
return n &lt; Date.UTC(2004, 0, 1); // &lt; Jan 1 2004
},
...
@ -2588,16 +2595,17 @@ $(function(){
// i = column index
// $r = jQuery element of current row
// c = table.config
// data = combined filter data - see filter widget "custom searches" demo, look under "How to add Custom filter types"
filter_functions: {
// Add these options to the select dropdown (regex example)
2 : {
"A - D" : function(e, n, f, i, $r, c) { return /^[A-D]/.test(e); },
"E - H" : function(e, n, f, i, $r, c) { return /^[E-H]/.test(e); },
"I - L" : function(e, n, f, i, $r, c) { return /^[I-L]/.test(e); },
"M - P" : function(e, n, f, i, $r, c) { return /^[M-P]/.test(e); },
"Q - T" : function(e, n, f, i, $r, c) { return /^[Q-T]/.test(e); },
"U - X" : function(e, n, f, i, $r, c) { return /^[U-X]/.test(e); },
"Y - Z" : function(e, n, f, i, $r, c) { return /^[Y-Z]/.test(e); }
"A - D" : function(e, n, f, i, $r, c, data) { return /^[A-D]/.test(e); },
"E - H" : function(e, n, f, i, $r, c, data) { return /^[E-H]/.test(e); },
"I - L" : function(e, n, f, i, $r, c, data) { return /^[I-L]/.test(e); },
"M - P" : function(e, n, f, i, $r, c, data) { return /^[M-P]/.test(e); },
"Q - T" : function(e, n, f, i, $r, c, data) { return /^[Q-T]/.test(e); },
"U - X" : function(e, n, f, i, $r, c, data) { return /^[U-X]/.test(e); },
"Y - Z" : function(e, n, f, i, $r, c, data) { return /^[Y-Z]/.test(e); }
}
}
}
@ -2615,14 +2623,15 @@ $(function(){
// i = column index
// $r = jQuery element of current row
// c = table.config
// data = combined filter data - see filter widget "custom searches" demo, look under "How to add Custom filter types"
filter_functions: {
// Add these options to the select dropdown (numerical comparison example)
// Note that only the normalized (n) value will contain numerical data
// If you use the exact text, you'll need to parse it (parseFloat or parseInt)
4 : {
"&lt; $10" : function(e, n, f, i, $r, c) { return n &lt; 10; },
"$10 - $100" : function(e, n, f, i, $r, c) { return n &gt;= 10 && n &lt;=100; },
"&gt; $100" : function(e, n, f, i, $r, c) { return n &gt; 100; }
"&lt; $10" : function(e, n, f, i, $r, c, data) { return n &lt; 10; },
"$10 - $100" : function(e, n, f, i, $r, c, data) { return n &gt;= 10 && n &lt;=100; },
"&gt; $100" : function(e, n, f, i, $r, c, data) { return n &gt; 100; }
}
}
}
@ -2643,9 +2652,10 @@ $(function(){
// i = column index
// $r = jQuery element of current row
// c = table.config
// data = combined filter data - see filter widget "custom searches" demo, look under "How to add Custom filter types"
filter_functions: {
// Exact match only
1 : function(e, n, f, i, $r, c) {
1 : function(e, n, f, i, $r, c, data) {
return e === f;
}
}
@ -2903,7 +2913,7 @@ $('table').trigger('search', false);</pre></div>
});
});</pre></div>
</td>
<td></td>
<td><a href="example-widget-filter-custom.html#custom_filter_function">Example</a></td>
</tr>
<tr id="widget-filter-selectsource">
@ -3006,9 +3016,9 @@ $('table').trigger('search', false);</pre></div>
filter_functions: {
// Add these options to the select dropdown (regex example)
1 : {
"<10|Less than 10" : function(e, n, f, i, $r, c) { return n < 10; },
"10 - 100|Between 10 & 100" : function(e, n, f, i, $r, c) { return n >= 10 && n <=100; },
">100|Greater than 100" : function(e, n, f, i, $r, c) { return n > 100; }
"&lt;10|Less than 10" : function(e, n, f, i, $r, c, data) { return n &lt; 10; },
"10 - 100|Between 10 & 100" : function(e, n, f, i, $r, c, data) { return n &gt;= 10 && n &lt;=100; },
"&gt;100|Greater than 100" : function(e, n, f, i, $r, c, data) { return n &gt; 100; }
}
},
// filter_selectSource array text left of the separator is added to the option value, right into the option text

View File

@ -4,7 +4,7 @@
*/
/*! tablesorter (FORK) - updated 04-30-2015 (v2.21.5)*/
/*! tablesorter (FORK) - updated 05-05-2015 (v2.21.5)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -251,6 +251,29 @@
return ts.getParserById('text');
}
// centralized function to extract/parse cell contents
function getParsedText( c, cell, colIndex, txt ) {
var val = '',
parser = c.parsers[ colIndex ],
extractor = c.extractors[ colIndex ];
txt = txt || ts.getElementText( c, cell, colIndex );
if ( parser ) {
// do extract before parsing if there is one
if ( extractor && typeof extractor.format === 'function' ) {
txt = extractor.format( txt, c.table, cell, colIndex );
}
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
val = parser.id === 'no-parser' ? '' :
// make sure txt is a string (extractor may have converted it)
parser.format( '' + txt, c.table, cell, colIndex );
if ( c.ignoreCase && typeof val === 'string' ) {
val = val.toLowerCase();
}
}
return val;
}
function buildParserCache(table) {
var c = table.config,
// update table bodies in case we start with an empty table
@ -314,11 +337,10 @@
/* utils */
function buildCache(table) {
var cc, t, tx, v, i, j, k, $row, cols, cacheTime,
var cc, t, v, i, j, k, $row, cols, cacheTime,
totalRows, rowData, colMax,
c = table.config,
$tb = c.$tbodies,
extractors = c.extractors,
parsers = c.parsers;
c.cache = {};
c.totalRows = 0;
@ -367,7 +389,7 @@
}
rowData.$row = $row;
rowData.order = i; // add original row position to rowCache
for (j = 0; j < c.columns; ++j) {
for ( j = 0; j < c.columns; ++j ) {
if (typeof parsers[j] === 'undefined') {
if (c.debug) {
log('No parser found for cell:', $row[0].cells[j], 'does it have a header?');
@ -376,24 +398,16 @@
}
t = ts.getElementText(c, $row[0].cells[j], j);
rowData.raw.push(t); // save original row text
// do extract before parsing if there is one
if (typeof extractors[j].id === 'undefined') {
tx = t;
} else {
tx = extractors[j].format(t, table, $row[0].cells[j], j);
}
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(tx, table, $row[0].cells[j], j);
cols.push( c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v );
if ((parsers[j].type || '').toLowerCase() === 'numeric') {
v = getParsedText( c, $row[ 0 ].cells[ j ], j, t );
cols.push( v );
if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
// determine column max value (ignore sign)
colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0);
colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 );
}
}
// ensure rowData is always in the same location (after the last column)
cols[c.columns] = rowData;
cc.normalized.push(cols);
cols[ c.columns ] = rowData;
cc.normalized.push( cols );
}
cc.colMax = colMax;
// total up rows, not including child rows
@ -917,35 +931,31 @@
table.isUpdating = true;
$table.find(c.selectorRemove).remove();
// get position from the dom
var v, t, row, icell,
var t, row, icell, cache,
$tb = c.$tbodies,
$cell = $(cell),
// update cache - format: function(s, table, cell, cellIndex)
// no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
tbcache = c.cache[ tbdy ],
$row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
cell = $cell[0]; // in case cell is a jQuery object
// tbody may not exist if update is initialized while tbody is removed for processing
if ($tb.length && tbdy >= 0) {
row = $tb.eq(tbdy).find('tr').index( $row );
row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
cache = tbcache.normalized[ row ];
icell = $cell.index();
c.cache[tbdy].normalized[row][c.columns].$row = $row;
if (typeof c.extractors[icell].id === 'undefined') {
t = ts.getElementText(c, cell, icell);
} else {
t = c.extractors[icell].format( ts.getElementText(c, cell, icell), table, cell, icell );
}
v = c.parsers[icell].id === 'no-parser' ? '' :
c.parsers[icell].format( t, table, cell, icell );
c.cache[tbdy].normalized[row][icell] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
if ((c.parsers[icell].type || '').toLowerCase() === 'numeric') {
t = getParsedText( c, cell, icell );
cache[ icell ] = t;
cache[ c.columns ].$row = $row;
if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
// update column max value (ignore sign)
c.cache[tbdy].colMax[icell] = Math.max(Math.abs(v) || 0, c.cache[tbdy].colMax[icell] || 0);
tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0);
}
v = resort !== 'undefined' ? resort : c.resort;
if (v !== false) {
t = resort !== 'undefined' ? resort : c.resort;
if (t !== false) {
// widgets will be reapplied
checkResort(c, v, callback);
checkResort(c, t, callback);
} else {
// don't reapply widgets is resort is false, just in case it causes
// problems with element focus
@ -965,7 +975,7 @@
commonUpdate(table, resort, callback);
} else {
$row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
var i, j, l, t, v, rowData, cells,
var i, j, l, rowData, cells,
rows = $row.filter('tr').length,
tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
// fixes adding rows to an empty table - see issue #179
@ -983,14 +993,7 @@
};
// add each cell
for (j = 0; j < l; j++) {
if (typeof c.extractors[j].id === 'undefined') {
t = ts.getElementText(c, $row[i].cells[j], j);
} else {
t = c.extractors[j].format( ts.getElementText(c, $row[i].cells[j], j), table, $row[i].cells[j], j );
}
v = c.parsers[j].id === 'no-parser' ? '' :
c.parsers[j].format( t, table, $row[i].cells[j], j );
cells[j] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
cells[j] = getParsedText( c, $row[i].cells[j], j );
if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
// update column max value (ignore sign)
c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
@ -2614,11 +2617,19 @@ ts.filter = {
types: {
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test(data.iFilter) ) {
if ( ts.filter.regex.regex.test(data.filter) ) {
var matches,
regex = ts.filter.regex.regex.exec(data.iFilter);
wo = c.widgetOptions,
// cache regex per column for optimal speed
regex = wo.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
matches = new RegExp(regex[1], regex[2]).test( data.iExact );
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] );
}
matches = regex.test( data.exact );
} catch (error) {
matches = false;
}
@ -2777,6 +2788,7 @@ 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*=","]';
@ -3302,7 +3314,7 @@ ts.filter = {
},
findRows: function(table, filters, combinedFilters) {
if (table.config.lastCombinedFilter === combinedFilters || !table.config.widgetOptions.filter_initialized) { return; }
var len, norm_rows, $rows, rowIndex, tbodyIndex, $tbody, $cells, $cell, columnIndex,
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,
@ -3310,10 +3322,13 @@ ts.filter = {
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
data = { anyMatch: false },
data = { anyMatch: false, filters: filters },
// 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 ||
@ -3435,30 +3450,32 @@ ts.filter = {
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;
// 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 = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
childRow = data.$row.nextUntil('tr:not(.' + c.cssChildRow + ')');
// 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;
$cells = $rows.eq(rowIndex).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 = $cells.map(function(i){
data.rowArray = data.$cells.map(function(i){
if ( $.inArray(i, columnIndex) > -1 ) {
var txt;
if (data.parsed[i]) {
txt = data.cacheArray[i];
} else {
txt = this ? this.getAttribute( c.textAttribute ) || this.textContent || $(this).text() : '';
txt = data.rawArray[i];
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
if (c.sortLocaleCompare) {
txt = ts.replaceAccents(txt);
@ -3513,8 +3530,7 @@ ts.filter = {
if (wo.filter_useParsedData || data.parsed[columnIndex]) {
data.exact = data.cache;
} else {
val = $cells[columnIndex];
result = val ? $.trim( val.getAttribute( c.textAttribute ) || val.textContent || $cells.eq(columnIndex).text() ) : '';
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;
@ -3546,10 +3562,10 @@ ts.filter = {
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, $rows.eq(rowIndex), c);
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, $rows.eq(rowIndex), c);
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
}
}
if (filterMatched === null) {
@ -3577,7 +3593,7 @@ ts.filter = {
showRow = (result) ? showRow : false;
}
}
$rows.eq(rowIndex)
data.$row
.toggleClass(wo.filter_filteredRow, !showRow)[0]
.display = showRow ? '' : 'none';
if (childRow.length) {
@ -3701,10 +3717,8 @@ ts.filter = {
if (wo.filter_useParsedData || c.parsers[column].parsed || c.$headerIndexed[column].hasClass('filter-parsed')) {
arry.push( '' + cache.normalized[rowIndex][column] );
} else {
cell = row.cells[column];
if (cell) {
arry.push( $.trim( cell.getAttribute( c.textAttribute ) || cell.textContent || $(cell).text() ) );
}
// get raw cached data instead of content directly from the cells
arry.push( cache.normalized[rowIndex][c.columns].raw[column] );
}
}
}

View File

@ -4,7 +4,7 @@
*/
/*! tablesorter (FORK) - updated 04-16-2015 (v2.21.5)*/
/*! tablesorter (FORK) - updated 05-05-2015 (v2.21.5)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -472,11 +472,19 @@ ts.filter = {
types: {
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test(data.iFilter) ) {
if ( ts.filter.regex.regex.test(data.filter) ) {
var matches,
regex = ts.filter.regex.regex.exec(data.iFilter);
wo = c.widgetOptions,
// cache regex per column for optimal speed
regex = wo.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
matches = new RegExp(regex[1], regex[2]).test( data.iExact );
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] );
}
matches = regex.test( data.exact );
} catch (error) {
matches = false;
}
@ -635,6 +643,7 @@ 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*=","]';
@ -1160,7 +1169,7 @@ ts.filter = {
},
findRows: function(table, filters, combinedFilters) {
if (table.config.lastCombinedFilter === combinedFilters || !table.config.widgetOptions.filter_initialized) { return; }
var len, norm_rows, $rows, rowIndex, tbodyIndex, $tbody, $cells, $cell, columnIndex,
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,
@ -1168,10 +1177,13 @@ ts.filter = {
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
data = { anyMatch: false },
data = { anyMatch: false, filters: filters },
// 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 ||
@ -1293,30 +1305,32 @@ ts.filter = {
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;
// 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 = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
childRow = data.$row.nextUntil('tr:not(.' + c.cssChildRow + ')');
// 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;
$cells = $rows.eq(rowIndex).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 = $cells.map(function(i){
data.rowArray = data.$cells.map(function(i){
if ( $.inArray(i, columnIndex) > -1 ) {
var txt;
if (data.parsed[i]) {
txt = data.cacheArray[i];
} else {
txt = this ? this.getAttribute( c.textAttribute ) || this.textContent || $(this).text() : '';
txt = data.rawArray[i];
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
if (c.sortLocaleCompare) {
txt = ts.replaceAccents(txt);
@ -1371,8 +1385,7 @@ ts.filter = {
if (wo.filter_useParsedData || data.parsed[columnIndex]) {
data.exact = data.cache;
} else {
val = $cells[columnIndex];
result = val ? $.trim( val.getAttribute( c.textAttribute ) || val.textContent || $cells.eq(columnIndex).text() ) : '';
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;
@ -1404,10 +1417,10 @@ ts.filter = {
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, $rows.eq(rowIndex), c);
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, $rows.eq(rowIndex), c);
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
}
}
if (filterMatched === null) {
@ -1435,7 +1448,7 @@ ts.filter = {
showRow = (result) ? showRow : false;
}
}
$rows.eq(rowIndex)
data.$row
.toggleClass(wo.filter_filteredRow, !showRow)[0]
.display = showRow ? '' : 'none';
if (childRow.length) {
@ -1559,10 +1572,8 @@ ts.filter = {
if (wo.filter_useParsedData || c.parsers[column].parsed || c.$headerIndexed[column].hasClass('filter-parsed')) {
arry.push( '' + cache.normalized[rowIndex][column] );
} else {
cell = row.cells[column];
if (cell) {
arry.push( $.trim( cell.getAttribute( c.textAttribute ) || cell.textContent || $(cell).text() ) );
}
// get raw cached data instead of content directly from the cells
arry.push( cache.normalized[rowIndex][c.columns].raw[column] );
}
}
}

View File

@ -796,7 +796,7 @@ ts.filter = {
},
findRows: function(table, filters, combinedFilters) {
if (table.config.lastCombinedFilter === combinedFilters || !table.config.widgetOptions.filter_initialized) { return; }
var len, norm_rows, $rows, rowIndex, tbodyIndex, $tbody, $cells, $cell, columnIndex,
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,
@ -804,7 +804,7 @@ ts.filter = {
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
data = { anyMatch: false },
data = { anyMatch: false, filters: filters },
// anyMatch really screws up with these types of filters
noAnyMatch = [ 'range', 'notMatch', 'operators' ];
@ -932,30 +932,32 @@ ts.filter = {
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;
// 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 = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
childRow = data.$row.nextUntil('tr:not(.' + c.cssChildRow + ')');
// 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;
$cells = $rows.eq(rowIndex).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 = $cells.map(function(i){
data.rowArray = data.$cells.map(function(i){
if ( $.inArray(i, columnIndex) > -1 ) {
var txt;
if (data.parsed[i]) {
txt = data.cacheArray[i];
} else {
txt = this ? this.getAttribute( c.textAttribute ) || this.textContent || $(this).text() : '';
txt = data.rawArray[i];
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
if (c.sortLocaleCompare) {
txt = ts.replaceAccents(txt);
@ -1010,8 +1012,7 @@ ts.filter = {
if (wo.filter_useParsedData || data.parsed[columnIndex]) {
data.exact = data.cache;
} else {
val = $cells[columnIndex];
result = val ? $.trim( val.getAttribute( c.textAttribute ) || val.textContent || $cells.eq(columnIndex).text() ) : '';
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;
@ -1043,10 +1044,10 @@ ts.filter = {
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, $rows.eq(rowIndex), c);
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, $rows.eq(rowIndex), c);
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, data.$row, c, data);
}
}
if (filterMatched === null) {
@ -1074,7 +1075,7 @@ ts.filter = {
showRow = (result) ? showRow : false;
}
}
$rows.eq(rowIndex)
data.$row
.toggleClass(wo.filter_filteredRow, !showRow)[0]
.display = showRow ? '' : 'none';
if (childRow.length) {
@ -1198,10 +1199,8 @@ ts.filter = {
if (wo.filter_useParsedData || c.parsers[column].parsed || c.$headerIndexed[column].hasClass('filter-parsed')) {
arry.push( '' + cache.normalized[rowIndex][column] );
} else {
cell = row.cells[column];
if (cell) {
arry.push( $.trim( cell.getAttribute( c.textAttribute ) || cell.textContent || $(cell).text() ) );
}
// get raw cached data instead of content directly from the cells
arry.push( cache.normalized[rowIndex][c.columns].raw[column] );
}
}
}