mirror of
https://github.com/Mottie/tablesorter.git
synced 2024-11-15 23:54:22 +00:00
Filter: add data parameter to filter_functions. See #891
This commit is contained in:
parent
a327084b16
commit
b591583669
136
dist/js/jquery.tablesorter.combined.js
vendored
136
dist/js/jquery.tablesorter.combined.js
vendored
@ -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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
dist/js/jquery.tablesorter.combined.min.js
vendored
8
dist/js/jquery.tablesorter.combined.min.js
vendored
File diff suppressed because one or more lines are too long
87
dist/js/jquery.tablesorter.js
vendored
87
dist/js/jquery.tablesorter.js
vendored
@ -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);
|
||||
|
4
dist/js/jquery.tablesorter.min.js
vendored
4
dist/js/jquery.tablesorter.min.js
vendored
File diff suppressed because one or more lines are too long
49
dist/js/jquery.tablesorter.widgets.js
vendored
49
dist/js/jquery.tablesorter.widgets.js
vendored
@ -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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
dist/js/jquery.tablesorter.widgets.min.js
vendored
6
dist/js/jquery.tablesorter.widgets.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/widgets/widget-filter.min.js
vendored
2
dist/js/widgets/widget-filter.min.js
vendored
File diff suppressed because one or more lines are too long
@ -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> & 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> & 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>
|
||||
|
@ -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 "i" 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 : {
|
||||
"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); }
|
||||
}
|
||||
|
||||
}</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 : {
|
||||
"< $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; }
|
||||
}
|
||||
}</pre></li>
|
||||
<li>See the "Filter function information" section below.</li>
|
||||
<li>See the "Filter function information" 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 "filter-match" 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> "filter-match" 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">
|
||||
|
@ -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"><th data-value="<=100">Price</th></pre>
|
||||
or, set the header cell's jQuery data
|
||||
<pre class="prettyprint lang-javascript">$('.tablesorter th:eq(0)').data('value', '<=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 "2?%" 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>
|
||||
|
@ -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">†</span> Filter Widget (<span class="version updated">v2.21.5</span>):
|
||||
<li><span class="results">†</span> Filter Widget (<span class="version updated">v2.21.6</span>):
|
||||
<ul>
|
||||
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.18.1</span>)</li>
|
||||
<li><a href="example-widget-filter-any-match.html">external option (match any column)</a> (<span class="version">v2.13.3</span>; <span class="version updated">v2.20.0</span>)</li>
|
||||
<li><a href="example-widget-filter-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" : {
|
||||
"< 2004" : function (e, n, f, i, $r, c) {
|
||||
"< 2004" : function (e, n, f, i, $r, c, data) {
|
||||
return n < Date.UTC(2004, 0, 1); // < 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 : {
|
||||
"< $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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
"<10|Less than 10" : function(e, n, f, i, $r, c, data) { return n < 10; },
|
||||
"10 - 100|Between 10 & 100" : function(e, n, f, i, $r, c, data) { return n >= 10 && n <=100; },
|
||||
">100|Greater than 100" : function(e, n, f, i, $r, c, data) { return n > 100; }
|
||||
}
|
||||
},
|
||||
// filter_selectSource array text left of the separator is added to the option value, right into the option text
|
||||
|
@ -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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user