2015-10-31 16:06:09 +00:00
/*! Widget: filter - updated 10/31/2015 (v2.24.0) */
2015-10-31 15:08:21 +00:00
/ *
* Requires tablesorter v2 . 8 + and jQuery 1.7 +
* by Rob Garrison
* /
! function ( a ) { "use strict" ; var b , c = a . tablesorter || { } , d = c . css ; a . extend ( d , { filterRow : "tablesorter-filter-row" , filter : "tablesorter-filter" , filterDisabled : "disabled" , filterRowHide : "hideme" } ) , c . addWidget ( { id : "filter" , priority : 50 , options : { filter _childRows : ! 1 , // if true, filter includes child row content in the search
filter _childByColumn : ! 1 , // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
filter _childWithSibs : ! 0 , // if true, include matching child row siblings
filter _columnFilters : ! 0 , // if true, a filter will be added to the top of each table column
filter _columnAnyMatch : ! 0 , // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
filter _cellFilter : "" , // css class name added to the filter cell ( string or array )
filter _cssFilter : "" , // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
filter _defaultFilter : { } , // add a default column filter type '~{query}' to make fuzzy searches default; '{q1} AND {q2}' to make all searches use a logical AND.
filter _excludeFilter : { } , // filters to exclude, per column
filter _external : "" , // jQuery selector string ( or jQuery object ) of external filters
filter _filteredRow : "filtered" , // class added to filtered rows; needed by pager plugin
filter _formatter : null , // add custom filter elements to the filter row
filter _functions : null , // add custom filter functions using this option
filter _hideEmpty : ! 0 , // hide filter row when table is empty
filter _hideFilters : ! 1 , // collapse filter row when mouse leaves the area
filter _ignoreCase : ! 0 , // if true, make all searches case-insensitive
filter _liveSearch : ! 0 , // if true, search column content while the user types ( with a delay )
filter _onlyAvail : "filter-onlyAvail" , // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
filter _placeholder : { search : "" , select : "" } , // default placeholder text ( overridden by any header 'data-placeholder' setting )
filter _reset : null , // jQuery selector string of an element used to reset the filters
filter _saveFilters : ! 1 , // Use the $.tablesorter.storage utility to save the most recent filters
filter _searchDelay : 300 , // typing delay in milliseconds before starting a search
filter _searchFiltered : ! 0 , // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
filter _selectSource : null , // include a function to return an array of values to be added to the column filter select
filter _startsWith : ! 1 , // if true, filter start from the beginning of the cell contents
filter _useParsedData : ! 1 , // filter all data using parsed content
filter _serversideFiltering : ! 1 , // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
filter _defaultAttrib : "data-value" , // data attribute in the header cell that contains the default filter value
filter _selectSourceSeparator : "|" } , format : function ( a , c , d ) { c . $table . hasClass ( "hasFilters" ) || b . init ( a , c , d ) } , remove : function ( b , e , f , g ) { var h , i , j = e . $table , k = e . $tbodies , l = "addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search " . split ( " " ) . join ( e . namespace + "filter " ) ; if ( j . removeClass ( "hasFilters" ) . unbind ( l . replace ( c . regex . spaces , " " ) ) . find ( "." + d . filterRow ) . remove ( ) , ! g ) { for ( h = 0 ; h < k . length ; h ++ ) i = c . processTbody ( b , k . eq ( h ) , ! 0 ) , i . children ( ) . removeClass ( f . filter _filteredRow ) . show ( ) , c . processTbody ( b , i , ! 1 ) ; f . filter _reset && a ( document ) . undelegate ( f . filter _reset , "click" + e . namespace + "filter" ) } } } ) , b = c . filter = {
// regex used in filter 'check' functions - not for general use and not documented
regex : { regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/ , // regex to test for regex
child : /tablesorter-childRow/ , // child row class name; this gets updated in the script
filtered : /filtered/ , // filtered (hidden) row class name; updated in the script
type : /undefined|number/ , // check type
exact : /(^[\"\'=]+)|([\"\'=]+$)/g , // exact match (allow '==')
operators : /[<>=]/g , // replace operators
query : "(q|query)" , // replace filter queries
wild01 : /\?/g , // wild card match 0 or 1
wild0More : /\*/g , // wild care match 0 or more
quote : /\"/g , isNeg1 : /(>=?\s*-\d)/ , isNeg2 : /(<=?\s*\d)/ } ,
// function( c, data ) { }
// c = table.config
// data.$row = jQuery object of the row currently being processed
// data.$cells = jQuery object of all cells within the current row
// data.filters = array of filters for all columns ( some may be undefined )
// data.filter = filter for the current column
// data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true )
// data.exact = table cell text ( or parsed data if column parser enabled; may be a number & not a string )
// data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true; may be a number & not a string )
// data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true )
// data.cacheArray = An array of parsed content from each table cell in the row being processed
// data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types : { or : function ( c , d , e ) { if ( b . regex . orTest . test ( d . iFilter ) || b . regex . orSplit . test ( d . filter ) ) { var f , g , h , i ,
// duplicate data but split filter
j = a . extend ( { } , d ) , k = d . index , l = d . parsed [ k ] , m = d . filter . split ( b . regex . orSplit ) , n = d . iFilter . split ( b . regex . orSplit ) , o = m . length ; for ( f = 0 ; o > f ; f ++ ) { j . nestedFilters = ! 0 , j . filter = "" + ( b . parseFilter ( c , m [ f ] , k , l ) || "" ) , j . iFilter = "" + ( b . parseFilter ( c , n [ f ] , k , l ) || "" ) , h = "(" + ( b . parseFilter ( c , j . filter , k , l ) || "" ) + ")" ; try { if ( i = new RegExp ( d . isMatch ? h : "^" + h + "$" , c . widgetOptions . filter _ignoreCase ? "i" : "" ) , g = i . test ( j . exact ) || b . processTypes ( c , j , e ) ) return g } catch ( p ) { return null } }
// may be null from processing types
return g || ! 1 } return null } ,
// Look for an AND or && operator ( logical and )
and : function ( c , d , e ) { if ( b . regex . andTest . test ( d . filter ) ) { var f , g , h , i , j ,
// duplicate data but split filter
k = a . extend ( { } , d ) , l = d . index , m = d . parsed [ l ] , n = d . filter . split ( b . regex . andSplit ) , o = d . iFilter . split ( b . regex . andSplit ) , p = n . length ; for ( f = 0 ; p > f ; f ++ ) { k . nestedFilters = ! 0 , k . filter = "" + ( b . parseFilter ( c , n [ f ] , l , m ) || "" ) , k . iFilter = "" + ( b . parseFilter ( c , o [ f ] , l , m ) || "" ) , i = ( "(" + ( b . parseFilter ( c , k . filter , l , m ) || "" ) + ")" ) . replace ( b . regex . wild01 , "\\S{1}" ) . replace ( b . regex . wild0More , "\\S*" ) ; try {
// use try/catch just in case RegExp is invalid
j = new RegExp ( d . isMatch ? i : "^" + i + "$" , c . widgetOptions . filter _ignoreCase ? "i" : "" ) ,
// look for an exact match with the 'and' unless the 'filter-match' class is found
h = j . test ( k . exact ) || b . processTypes ( c , k , e ) , g = 0 === f ? h : g && h } catch ( q ) { return null } }
// may be null from processing types
return g || ! 1 } return null } ,
// Look for regex
regex : function ( a , c ) { if ( b . regex . regex . test ( c . filter ) ) { var d ,
// cache regex per column for optimal speed
e = c . filter _regexCache [ c . index ] || b . regex . regex . exec ( c . filter ) , f = e instanceof RegExp ; try { f || (
// force case insensitive search if ignoreCase option set?
// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
c . filter _regexCache [ c . index ] = e = new RegExp ( e [ 1 ] , e [ 2 ] ) ) , d = e . test ( c . exact ) } catch ( g ) { d = ! 1 } return d } return null } ,
// Look for operators >, >=, < or <=
operators : function ( d , e ) {
// ignore empty strings... because '' < 10 is true
if ( b . regex . operTest . test ( e . iFilter ) && "" !== e . iExact ) { var f , g , h , i = d . table , j = e . index , k = e . parsed [ j ] , l = c . formatFloat ( e . iFilter . replace ( b . regex . operators , "" ) , i ) , m = d . parsers [ j ] , n = l ;
// parse filter value in case we're comparing numbers ( dates )
// iExact may be numeric - see issue #149;
// check if cached is defined, because sometimes j goes out of range? ( numeric columns )
// keep showing all rows if nothing follows the operator
return ( k || "numeric" === m . type ) && ( h = a . trim ( "" + e . iFilter . replace ( b . regex . operators , "" ) ) , g = b . parseFilter ( d , h , j , ! 0 ) , l = "number" != typeof g || "" === g || isNaN ( g ) ? l : g ) , ! k && "numeric" !== m . type || isNaN ( l ) || "undefined" == typeof e . cache ? ( h = isNaN ( e . iExact ) ? e . iExact . replace ( c . regex . nondigit , "" ) : e . iExact , f = c . formatFloat ( h , i ) ) : f = e . cache , b . regex . gtTest . test ( e . iFilter ) ? g = b . regex . gteTest . test ( e . iFilter ) ? f >= l : f > l : b . regex . ltTest . test ( e . iFilter ) && ( g = b . regex . lteTest . test ( e . iFilter ) ? l >= f : l > f ) , g || "" !== n || ( g = ! 0 ) , g } return null } ,
// Look for a not match
notMatch : function ( c , d ) { if ( b . regex . notTest . test ( d . iFilter ) ) { var e , f = d . iFilter . replace ( "!" , "" ) , g = b . parseFilter ( c , f , d . index , d . parsed [ d . index ] ) || "" ;
// look for exact not matches - see #628
return b . regex . exact . test ( g ) ? ( g = g . replace ( b . regex . exact , "" ) , "" === g ? ! 0 : a . trim ( g ) !== d . iExact ) : ( e = d . iExact . search ( a . trim ( g ) ) , "" === g ? ! 0 : ! ( c . widgetOptions . filter _startsWith ? 0 === e : e >= 0 ) ) } return null } ,
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
exact : function ( c , d ) { /*jshint eqeqeq:false */
if ( b . regex . exact . test ( d . iFilter ) ) { var e = d . iFilter . replace ( b . regex . exact , "" ) , f = b . parseFilter ( c , e , d . index , d . parsed [ d . index ] ) || "" ; return d . anyMatch ? a . inArray ( f , d . rowArray ) >= 0 : f == d . iExact } return null } ,
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range : function ( a , d ) { if ( b . regex . toTest . test ( d . iFilter ) ) { var e , f , g , h , i = a . table , j = d . index , k = d . parsed [ j ] ,
// make sure the dash is for a range and not indicating a negative number
l = d . iFilter . split ( b . regex . toSplit ) ;
// parse filter value in case we're comparing numbers ( dates )
return f = l [ 0 ] . replace ( c . regex . nondigit , "" ) || "" , g = c . formatFloat ( b . parseFilter ( a , f , j , k ) , i ) , f = l [ 1 ] . replace ( c . regex . nondigit , "" ) || "" , h = c . formatFloat ( b . parseFilter ( a , f , j , k ) , i ) , ( k || "numeric" === a . parsers [ j ] . type ) && ( e = a . parsers [ j ] . format ( "" + l [ 0 ] , i , a . $headers . eq ( j ) , j ) , g = "" === e || isNaN ( e ) ? g : e , e = a . parsers [ j ] . format ( "" + l [ 1 ] , i , a . $headers . eq ( j ) , j ) , h = "" === e || isNaN ( e ) ? h : e ) , ! k && "numeric" !== a . parsers [ j ] . type || isNaN ( g ) || isNaN ( h ) ? ( f = isNaN ( d . iExact ) ? d . iExact . replace ( c . regex . nondigit , "" ) : d . iExact , e = c . formatFloat ( f , i ) ) : e = d . cache , g > h && ( f = g , g = h , h = f ) , e >= g && h >= e || "" === g || "" === h } return null } ,
// Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function ( a , c ) { if ( b . regex . wildOrTest . test ( c . iFilter ) ) { var d = c . index , e = c . parsed [ d ] , f = "" + ( b . parseFilter ( a , c . iFilter , d , e ) || "" ) ;
// look for an exact match with the 'or' unless the 'filter-match' class is found
! b . regex . wildTest . test ( f ) && c . nestedFilters && ( f = c . isMatch ? f : "^(" + f + ")$" ) ;
// parsing the filter may not work properly when using wildcards =/
try { return new RegExp ( f . replace ( b . regex . wild01 , "\\S{1}" ) . replace ( b . regex . wild0More , "\\S*" ) , a . widgetOptions . filter _ignoreCase ? "i" : "" ) . test ( c . exact ) } catch ( g ) { return null } } return null } ,
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
fuzzy : function ( a , c ) { if ( b . regex . fuzzyTest . test ( c . iFilter ) ) { var d , e = 0 , f = c . iExact . length , g = c . iFilter . slice ( 1 ) , h = b . parseFilter ( a , g , c . index , c . parsed [ c . index ] ) || "" ; for ( d = 0 ; f > d ; d ++ ) c . iExact [ d ] === h [ e ] && ( e += 1 ) ; return e === h . length ? ! 0 : ! 1 } return null } } , init : function ( e , f , g ) {
// filter language options
c . language = a . extend ( ! 0 , { } , { to : "to" , or : "or" , and : "and" } , c . language ) ; var h , i , j , k , l , m , n , o , p , q = b . regex ; if ( f . $table . addClass ( "hasFilters" ) ,
// define timers so using clearTimeout won't cause an undefined error
g . filter _searchTimer = null , g . filter _initTimer = null , g . filter _formatterCount = 0 , g . filter _formatterInit = [ ] , g . filter _anyColumnSelector = '[data-column="all"],[data-column="any"]' , g . filter _multipleColumnSelector = '[data-column*="-"],[data-column*=","]' , n = "\\{" + b . regex . query + "\\}" , a . extend ( q , { child : new RegExp ( f . cssChildRow ) , filtered : new RegExp ( g . filter _filteredRow ) , alreadyFiltered : new RegExp ( "(\\s+(" + c . language . or + "|-|" + c . language . to + ")\\s+)" , "i" ) , toTest : new RegExp ( "\\s+(-|" + c . language . to + ")\\s+" , "i" ) , toSplit : new RegExp ( "(?:\\s+(?:-|" + c . language . to + ")\\s+)" , "gi" ) , andTest : new RegExp ( "\\s+(" + c . language . and + "|&&)\\s+" , "i" ) , andSplit : new RegExp ( "(?:\\s+(?:" + c . language . and + "|&&)\\s+)" , "gi" ) , orTest : /\|/ , orSplit : new RegExp ( "(?:\\s+(?:" + c . language . or + ")\\s+|\\|)" , "gi" ) , iQuery : new RegExp ( n , "i" ) , igQuery : new RegExp ( n , "ig" ) , operTest : /^[<>]=?/ , gtTest : />/ , gteTest : />=/ , ltTest : /</ , lteTest : /<=/ , notTest : /^\!/ , wildOrTest : /[\?\*\|]/ , wildTest : /\?\*/ , fuzzyTest : /^~/ , exactTest : /[=\"\|!]/ } ) , n = f . $headers . filter ( ".filter-false, .parser-false" ) . length , g . filter _columnFilters !== ! 1 && n !== f . $headers . length && b . buildRow ( e , f , g ) , j = "addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search " . split ( " " ) . join ( f . namespace + "filter " ) , f . $table . bind ( j , function ( c , h ) { return n = g . filter _hideEmpty && a . isEmptyObject ( f . cache ) && ! ( f . delayInit && "appendCache" === c . type ) , f . $table . find ( "." + d . filterRow ) . toggleClass ( g . filter _filteredRow , n ) , /(search|filter)/ . test ( c . type ) || ( c . stopPropagation ( ) , b . buildDefault ( e , ! 0 ) ) , "filterReset" === c . type ? ( f . $table . find ( "." + d . filter ) . add ( g . filter _$externalFilters ) . val ( "" ) , b . searching ( e , [ ] ) ) : "filterEnd" === c . type ? b . buildDefault ( e , ! 0 ) : ( h = "search" === c . type ? h : "updateComplete" === c . type ? f . $table . data ( "lastSearch" ) : "" , /(update|add)/ . test ( c . type ) && "updateComplete" !== c . type && ( f . lastCombinedFilter = null , f . lastSearch = [ ] ) , b . searching ( e , h , ! 0 ) ) , ! 1 } ) , g . filter _reset && ( g . filter _reset instanceof a ? g . filter _reset . click ( function ( ) { f . $table . trigger ( "filterReset" ) } ) : a ( g . filter _reset ) . length && a ( document ) . undelegate ( g . filter _reset , "click" + f . namespace + "filter" ) . delegate ( g . filter _reset , "click" + f . namespace + "filter" , function ( ) { f . $table . trigger ( "filterReset" ) } ) ) , g . filter _functions ) for ( l = 0 ; l < f . columns ; l ++ ) if ( o = c . getColumnData ( e , g . filter _functions , l ) ) if ( k = f . $headerIndexed [ l ] . removeClass ( "filter-select" ) , p = ! ( k . hasClass ( "filter-false" ) || k . hasClass ( "parser-false" ) ) , h = "" , o === ! 0 && p ) b . buildSelect ( e , l ) ; else if ( "object" == typeof o && p ) {
// add custom drop down list
for ( i in o ) "string" == typeof i && ( h += "" === h ? '<option value="">' + ( k . data ( "placeholder" ) || k . attr ( "data-placeholder" ) || g . filter _placeholder . select || "" ) + "</option>" : "" , n = i , j = i , i . indexOf ( g . filter _selectSourceSeparator ) >= 0 && ( n = i . split ( g . filter _selectSourceSeparator ) , j = n [ 1 ] , n = n [ 0 ] ) , h += "<option " + ( j === n ? "" : 'data-function-name="' + i + '" ' ) + 'value="' + n + '">' + j + "</option>" ) ; f . $table . find ( "thead" ) . find ( "select." + d . filter + '[data-column="' + l + '"]' ) . append ( h ) , j = g . filter _selectSource , o = "function" == typeof j ? ! 0 : c . getColumnData ( e , j , l ) , o &&
// updating so the extra options are appended
b . buildSelect ( f . table , l , "" , ! 0 , k . hasClass ( g . filter _onlyAvail ) ) }
// not really updating, but if the column has both the 'filter-select' class &
// filter_functions set to true, it would append the same options twice.
b . buildDefault ( e , ! 0 ) , b . bindSearch ( e , f . $table . find ( "." + d . filter ) , ! 0 ) , g . filter _external && b . bindSearch ( e , g . filter _external ) , g . filter _hideFilters && b . hideFilters ( f ) ,
// show processing icon
f . showProcessing && ( j = "filterStart filterEnd " . split ( " " ) . join ( f . namespace + "filter " ) , f . $table . unbind ( j . replace ( c . regex . spaces , " " ) ) . bind ( j , function ( b , g ) { k = g ? f . $table . find ( "." + d . header ) . filter ( "[data-column]" ) . filter ( function ( ) { return "" !== g [ a ( this ) . data ( "column" ) ] } ) : "" , c . isProcessing ( e , "filterStart" === b . type , g ? k : "" ) } ) ) ,
// set filtered rows count ( intially unfiltered )
f . filteredRows = f . totalRows , j = "tablesorter-initialized pagerBeforeInitialized " . split ( " " ) . join ( f . namespace + "filter " ) , f . $table . unbind ( j . replace ( c . regex . spaces , " " ) ) . bind ( j , function ( ) { var a = this . config . widgetOptions ; m = b . setDefaults ( e , f , a ) || [ ] , m . length && ( f . delayInit && "" === m . join ( "" ) || c . setFilters ( e , m , ! 0 ) ) , f . $table . trigger ( "filterFomatterUpdate" ) , setTimeout ( function ( ) { a . filter _initialized || b . filterInitComplete ( f ) } , 100 ) } ) , f . pager && f . pager . initialized && ! g . filter _initialized && ( f . $table . trigger ( "filterFomatterUpdate" ) , setTimeout ( function ( ) { b . filterInitComplete ( f ) } , 100 ) ) } ,
// $cell parameter, but not the config, is passed to the filter_formatters,
// so we have to work with it instead
formatterUpdated : function ( a , b ) {
// prevent error if $cell is undefined - see #1056
var c = a && a . closest ( "table" ) [ 0 ] . config . widgetOptions ; c && ! c . filter _initialized && (
// add updates by column since this function
// may be called numerous times before initialization
c . filter _formatterInit [ b ] = 1 ) } , filterInitComplete : function ( c ) { var d , e , f = c . widgetOptions , g = 0 , h = function ( ) { f . filter _initialized = ! 0 , c . $table . trigger ( "filterInit" , c ) , b . findRows ( c . table , c . $table . data ( "lastSearch" ) || [ ] ) } ; if ( a . isEmptyObject ( f . filter _formatter ) ) h ( ) ; else { for ( e = f . filter _formatterInit . length , d = 0 ; e > d ; d ++ ) 1 === f . filter _formatterInit [ d ] && g ++ ; clearTimeout ( f . filter _initTimer ) , f . filter _initialized || g !== f . filter _formatterCount ? f . filter _initialized || (
// fall back in case a filter_formatter doesn't call
// $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
f . filter _initTimer = setTimeout ( function ( ) { h ( ) } , 500 ) ) :
// filter widget initialized
h ( ) } } ,
// encode or decode filters for storage; see #1026
processFilters : function ( a , b ) { var c , d = b ? encodeURIComponent : decodeURIComponent , e = a . length ; for ( c = 0 ; e > c ; c ++ ) a [ c ] = d ( a [ c ] ) ; return a } , setDefaults : function ( d , e , f ) { var g , h , i , j , k ,
// get current ( default ) filters
l = c . getFilters ( d ) || [ ] ;
// if no filters saved, then check default settings
if ( f . filter _saveFilters && c . storage && ( h = c . storage ( d , "tablesorter-filters" ) || [ ] , g = a . isArray ( h ) , g && "" === h . join ( "" ) || ! g || ( l = b . processFilters ( h ) ) ) , "" === l . join ( "" ) ) for ( k = e . $headers . add ( f . filter _$externalFilters ) . filter ( "[" + f . filter _defaultAttrib + "]" ) , i = 0 ; i <= e . columns ; i ++ ) j = i === e . columns ? "all" : i , l [ i ] = k . filter ( '[data-column="' + j + '"]' ) . attr ( f . filter _defaultAttrib ) || l [ i ] || "" ; return e . $table . data ( "lastSearch" , l ) , l } , parseFilter : function ( a , b , c , d ) { return d ? a . parsers [ c ] . format ( b , a . table , [ ] , c ) : b } , buildRow : function ( b , e , f ) { var g , h , i , j , k , l , m , n , o ,
// c.columns defined in computeThIndexes()
p = f . filter _cellFilter , q = e . columns , r = a . isArray ( p ) , s = '<tr role="row" class="' + d . filterRow + " " + e . cssIgnoreRow + '">' ; for ( i = 0 ; q > i ; i ++ ) e . $headerIndexed [ i ] . length && ( s += '<td data-column="' + i + '"' , o = e . $headerIndexed [ i ] && e . $headerIndexed [ i ] [ 0 ] . colSpan || 0 , o > 1 && ( s += ' colspan="' + o + '"' ) , s += r ? p [ i ] ? ' class="' + p [ i ] + '"' : "" : "" !== p ? ' class="' + p + '"' : "" , s += "></td>" ) ;
// build each filter input
for ( e . $filters = a ( s += "</tr>" ) . appendTo ( e . $table . children ( "thead" ) . eq ( 0 ) ) . children ( "td" ) , i = 0 ; q > i ; i ++ ) l = ! 1 , j = e . $headerIndexed [ i ] , j && j . length && ( g = e . $filters . filter ( '[data-column="' + i + '"]' ) , n = c . getColumnData ( b , f . filter _functions , i ) , k = f . filter _functions && n && "function" != typeof n || j . hasClass ( "filter-select" ) , h = c . getColumnData ( b , e . headers , i ) , l = "false" === c . getData ( j [ 0 ] , h , "filter" ) || "false" === c . getData ( j [ 0 ] , h , "parser" ) , k ? s = a ( "<select>" ) . appendTo ( g ) : ( n = c . getColumnData ( b , f . filter _formatter , i ) , n ? ( f . filter _formatterCount ++ , s = n ( g , i ) , s && 0 === s . length && ( s = g . children ( "input" ) ) , s && ( 0 === s . parent ( ) . length || s . parent ( ) . length && s . parent ( ) [ 0 ] !== g [ 0 ] ) && g . append ( s ) ) : s = a ( '<input type="search">' ) . appendTo ( g ) , s && ( o = j . data ( "placeholder" ) || j . attr ( "data-placeholder" ) || f . filter _placeholder . search || "" , s . attr ( "placeholder" , o ) ) ) , s && ( m = ( a . isArray ( f . filter _cssFilter ) ? "undefined" != typeof f . filter _cssFilter [ i ] ? f . filter _cssFilter [ i ] || "" : "" : f . filter _cssFilter ) || "" , s . addClass ( d . filter + " " + m ) . attr ( "data-column" , i ) , l && ( s . attr ( "placeholder" , "" ) . addClass ( d . filterDisabled ) [ 0 ] . disabled = ! 0 ) ) ) } , bindSearch : function ( d , e , f ) { // allow passing a selector string
if ( d = a ( d ) [ 0 ] , e = a ( e ) , e . length ) { var g , h = d . config , i = h . widgetOptions , j = h . namespace + "filter" , k = i . filter _$externalFilters ; f !== ! 0 && ( g = i . filter _anyColumnSelector + "," + i . filter _multipleColumnSelector , i . filter _$anyMatch = e . filter ( g ) , k && k . length ? i . filter _$externalFilters = i . filter _$externalFilters . add ( e ) : i . filter _$externalFilters = e , c . setFilters ( d , h . $table . data ( "lastSearch" ) || [ ] , f === ! 1 ) ) ,
// unbind events
g = "keypress keyup search change " . split ( " " ) . join ( j + " " ) , e . attr ( "data-lastSearchTime" , ( new Date ) . getTime ( ) ) . unbind ( g . replace ( c . regex . spaces , " " ) ) . bind ( "keyup" + j , function ( c ) {
// emulate what webkit does.... escape clears the filter
if ( a ( this ) . attr ( "data-lastSearchTime" , ( new Date ) . getTime ( ) ) , 27 === c . which ) this . value = "" ; else { if ( i . filter _liveSearch === ! 1 ) return ; if ( "" !== this . value && ( "number" == typeof i . filter _liveSearch && this . value . length < i . filter _liveSearch || 13 !== c . which && 8 !== c . which && ( c . which < 32 || c . which >= 37 && c . which <= 40 ) ) ) return }
// change event = no delay; last true flag tells getFilters to skip newest timed input
b . searching ( d , ! 0 , ! 0 ) } ) . bind ( "search change keypress " . split ( " " ) . join ( j + " " ) , function ( c ) {
// don't get cached data, in case data-column changes dynamically
var e = parseInt ( a ( this ) . attr ( "data-column" ) , 10 ) ;
// don't allow 'change' event to process if the input value is the same - fixes #685
i . filter _initialized && ( 13 === c . which || "search" === c . type || "change" === c . type && this . value !== h . lastSearch [ e ] ) && ( c . preventDefault ( ) ,
// init search with no delay
a ( this ) . attr ( "data-lastSearchTime" , ( new Date ) . getTime ( ) ) , b . searching ( d , ! 1 , ! 0 ) ) } ) } } , searching : function ( a , c , d ) { var e = a . config . widgetOptions ; clearTimeout ( e . filter _searchTimer ) , "undefined" == typeof c || c === ! 0 ?
// delay filtering
e . filter _searchTimer = setTimeout ( function ( ) { b . checkFilters ( a , c , d ) } , e . filter _liveSearch ? e . filter _searchDelay : 10 ) :
// skip delay
b . checkFilters ( a , c , d ) } , checkFilters : function ( e , f , g ) { var h = e . config , i = h . widgetOptions , j = a . isArray ( f ) , k = j ? f : c . getFilters ( e , ! 0 ) , l = ( k || [ ] ) . join ( "" ) ; // combined filter values
// prevent errors if delay init is set
// combined filter values
// prevent errors if delay init is set
// update cache if delayInit set & pager has initialized ( after user initiates a search )
// add filter array back into inputs
// show/hide filter row as needed
// return if the last search is the same; but filter === false when updating the search
// see example-widget-filter.html filter toggle buttons
// force filter refresh
// give it time for the processing icon to kick in
return a . isEmptyObject ( h . cache ) ? void ( h . delayInit && h . pager && h . pager . initialized && c . updateCache ( h , function ( ) { b . checkFilters ( e , ! 1 , g ) } ) ) : ( j && ( c . setFilters ( e , k , ! 1 , g !== ! 0 ) , i . filter _initialized || ( h . lastCombinedFilter = "" ) ) , i . filter _hideFilters && h . $table . find ( "." + d . filterRow ) . trigger ( "" === l ? "mouseleave" : "mouseenter" ) , h . lastCombinedFilter !== l || f === ! 1 ? ( f === ! 1 && ( h . lastCombinedFilter = null , h . lastSearch = [ ] ) , i . filter _initialized && h . $table . trigger ( "filterStart" , [ k ] ) , h . showProcessing ? void setTimeout ( function ( ) { return b . findRows ( e , k , l ) , ! 1 } , 30 ) : ( b . findRows ( e , k , l ) , ! 1 ) ) : void 0 ) } , hideFilters : function ( b , e ) { var f , g = ( e || b . $table ) . find ( "." + d . filterRow ) . addClass ( d . filterRowHide ) ; g . bind ( "mouseenter mouseleave" , function ( c ) {
// save event object - http://bugs.jquery.com/ticket/12140
var e = c , g = a ( this ) ; clearTimeout ( f ) , f = setTimeout ( function ( ) { /enter|over/ . test ( e . type ) ? g . removeClass ( d . filterRowHide ) :
// don't hide if input has focus
// $( ':focus' ) needs jQuery 1.6+
a ( document . activeElement ) . closest ( "tr" ) [ 0 ] !== g [ 0 ] && "" === b . lastCombinedFilter && g . addClass ( d . filterRowHide ) } , 200 ) } ) . find ( "input, select" ) . bind ( "focus blur" , function ( e ) { var g = e , h = a ( this ) . closest ( "tr" ) ; clearTimeout ( f ) , f = setTimeout ( function ( ) { clearTimeout ( f ) ,
// don't hide row if any filter has a value
"" === c . getFilters ( b . $table ) . join ( "" ) && h . toggleClass ( d . filterRowHide , "focus" !== g . type ) } , 200 ) } ) } , defaultFilter : function ( c , d ) { if ( "" === c ) return c ; var e = b . regex . iQuery , f = d . match ( b . regex . igQuery ) . length , g = f > 1 ? a . trim ( c ) . split ( /\s/ ) : [ a . trim ( c ) ] , h = g . length - 1 , i = 0 , j = d ;
// replace all {query} with query words...
// if query = 'Bob', then convert mask from '!{query}' to '!Bob'
// if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank'
for ( 1 > h && f > 1 && (
// only one 'word' in query but mask has >1 slots
g [ 1 ] = g [ 0 ] ) ; e . test ( j ) ; ) j = j . replace ( e , g [ i ++ ] || "" ) , e . test ( j ) && h > i && "" !== ( g [ i ] || "" ) && ( j = d . replace ( e , j ) ) ; return j } , getLatestSearch : function ( b ) { return b ? b . sort ( function ( b , c ) { return a ( c ) . attr ( "data-lastSearchTime" ) - a ( b ) . attr ( "data-lastSearchTime" ) } ) : b || a ( ) } , multipleColumns : function ( c , d ) {
// look for multiple columns '1-3,4-6,8' in data-column
var e , f , g , h , i , j , k , l , m , n = c . widgetOptions ,
// only target 'all' column inputs on initialization
// & don't target 'all' column inputs if they don't exist
o = n . filter _initialized || ! d . filter ( n . filter _anyColumnSelector ) . length , p = [ ] , q = a . trim ( b . getLatestSearch ( d ) . attr ( "data-column" ) || "" ) ; if ( /^[0-9]+$/ . test ( q ) ) return parseInt ( q , 10 ) ;
// process column range
if ( o && /-/ . test ( q ) ) for ( f = q . match ( /(\d+)\s*-\s*(\d+)/g ) , m = f . length , l = 0 ; m > l ; l ++ ) { for ( g = f [ l ] . split ( /\s*-\s*/ ) , h = parseInt ( g [ 0 ] , 10 ) || 0 , i = parseInt ( g [ 1 ] , 10 ) || c . columns - 1 , h > i && ( e = h , h = i , i = e ) , i >= c . columns && ( i = c . columns - 1 ) ; i >= h ; h ++ ) p . push ( h ) ;
// remove processed range from val
q = q . replace ( f [ l ] , "" ) }
// process single columns
if ( o && /,/ . test ( q ) ) for ( j = q . split ( /\s*,\s*/ ) , m = j . length , k = 0 ; m > k ; k ++ ) "" !== j [ k ] && ( l = parseInt ( j [ k ] , 10 ) , l < c . columns && p . push ( l ) ) ;
// return all columns
if ( ! p . length ) for ( l = 0 ; l < c . columns ; l ++ ) p . push ( l ) ; return p } , processTypes : function ( c , d , e ) { var f , g = null , h = null ; for ( f in b . types ) a . inArray ( f , e . excludeMatch ) < 0 && null === h && ( h = b . types [ f ] ( c , d , e ) , null !== h && ( g = h ) ) ; return g } , processRow : function ( d , e , f ) { var g , h , i , j , k , l , m , n = b . regex , o = d . widgetOptions , p = ! 0 ,
// if wo.filter_$anyMatch data-column attribute is changed dynamically
// we don't want to do an "anyMatch" search on one column using data
// for the entire row - see #998
q = o . filter _$anyMatch && o . filter _$anyMatch . length ?
// look for multiple columns '1-3,4-6,8'
b . multipleColumns ( d , o . filter _$anyMatch ) : [ ] ; if ( e . $cells = e . $row . children ( ) , e . anyMatchFlag && q . length > 1 ) { if ( e . anyMatch = ! 0 , e . isMatch = ! 0 , e . rowArray = e . $cells . map ( function ( b ) { return a . inArray ( b , q ) > - 1 ? ( e . parsed [ b ] ? m = e . cacheArray [ b ] : ( m = e . rawArray [ b ] , m = a . trim ( o . filter _ignoreCase ? m . toLowerCase ( ) : m ) , d . sortLocaleCompare && ( m = c . replaceAccents ( m ) ) ) , m ) : void 0 } ) . get ( ) , e . filter = e . anyMatchFilter , e . iFilter = e . iAnyMatchFilter , e . exact = e . rowArray . join ( " " ) , e . iExact = o . filter _ignoreCase ? e . exact . toLowerCase ( ) : e . exact , e . cache = e . cacheArray . slice ( 0 , - 1 ) . join ( " " ) , f . excludeMatch = f . noAnyMatch , j = b . processTypes ( d , e , f ) , null !== j ) p = j ; else if ( o . filter _startsWith ) for ( p = ! 1 ,
// data.rowArray may not contain all columns
q = Math . min ( d . columns , e . rowArray . length ) ; ! p && q > 0 ; ) q -- , p = p || 0 === e . rowArray [ q ] . indexOf ( e . iFilter ) ; else p = ( e . iExact + e . childRowText ) . indexOf ( e . iFilter ) >= 0 ;
// no other filters to process
if ( e . anyMatch = ! 1 , e . filters . join ( "" ) === e . filter ) return p } for ( q = 0 ; q < d . columns ; q ++ ) e . filter = e . filters [ q ] , e . index = q ,
// filter types to exclude, per column
f . excludeMatch = f . excludeFilter [ q ] ,
// ignore if filter is empty or disabled
e . filter && ( e . cache = e . cacheArray [ q ] ,
// check if column data should be from the cell or from parsed data
o . filter _useParsedData || e . parsed [ q ] ? e . exact = e . cache : ( h = e . rawArray [ q ] || "" , e . exact = d . sortLocaleCompare ? c . replaceAccents ( h ) : h ) , e . iExact = ! n . type . test ( typeof e . exact ) && o . filter _ignoreCase ? e . exact . toLowerCase ( ) : e . exact , e . isMatch = d . $headerIndexed [ e . index ] . hasClass ( "filter-match" ) , h = p , l = o . filter _columnFilters ? d . $filters . add ( d . $externalFilters ) . filter ( '[data-column="' + q + '"]' ) . find ( "select option:selected" ) . attr ( "data-function-name" ) || "" : "" , d . sortLocaleCompare && ( e . filter = c . replaceAccents ( e . filter ) ) , i = ! 0 , o . filter _defaultFilter && n . iQuery . test ( f . defaultColFilter [ q ] ) && ( e . filter = b . defaultFilter ( e . filter , f . defaultColFilter [ q ] ) , i = ! 1 ) , e . iFilter = o . filter _ignoreCase ? ( e . filter || "" ) . toLowerCase ( ) : e . filter , k = f . functions [ q ] , g = d . $headerIndexed [ q ] . hasClass ( "filter-select" ) , j = null , ( k || g && i ) && ( k === ! 0 || g ? j = e . isMatch ? ( "" + e . iExact ) . search ( e . iFilter ) >= 0 : e . filter === e . exact : "function" == typeof k ? j = k ( e . exact , e . cache , e . filter , q , e . $row , d , e ) : "function" == typeof k [ l || e . filter ] && ( m = l || e . filter , j = k [ m ] ( e . exact , e . cache , e . filter , q , e . $row , d , e ) ) ) , null === j ? ( j = b . processTypes ( d , e , f ) , null !== j ? h = j : ( m = ( e . iExact + e . childRowText ) . indexOf ( b . parseFilter ( d , e . iFilter , q , e . parsed [ q ] ) ) , h = ! o . filter _startsWith && m >= 0 || o . filter _startsWith && 0 === m ) ) : h = j , p = h ? p : ! 1 ) ; return p } , findRows : function ( d , e , f ) { if ( d . config . lastCombinedFilter !== f && d . config . widgetOptions . filter _initialized ) { var g , h , i , j , k , l , m , n , o , p , q , r , s , t , u , v , w , x , y , z , A , B , C , D , E = a . extend ( [ ] , e ) , F = b . regex , G = d . config , H = G . widgetOptions ,
// data object passed to filters; anyMatch is a flag for the filters
I = { anyMatch : ! 1 , filters : e ,
// regex filter type cache
filter _regexCache : [ ] } , J = {
// anyMatch really screws up with these types of filters
noAnyMatch : [ "range" , "notMatch" , "operators" ] ,
// cache filter variables that use ts.getColumnData in the main loop
functions : [ ] , excludeFilter : [ ] , defaultColFilter : [ ] , defaultAnyFilter : c . getColumnData ( d , H . filter _defaultFilter , G . columns , ! 0 ) || "" } ; for (
// parse columns after formatter, in case the class is added at that point
I . parsed = G . $headers . map ( function ( b ) {
// force parsing if parser type is numeric
// getData won't return 'parsed' if other 'filter-' class names exist
// ( e.g. <th class="filter-select filter-parsed"> )
return G . parsers && G . parsers [ b ] && G . parsers [ b ] . parsed || c . getData && "parsed" === c . getData ( G . $headerIndexed [ b ] , c . getColumnData ( d , G . headers , b ) , "filter" ) || a ( this ) . hasClass ( "filter-parsed" ) } ) . get ( ) , o = 0 ; o < G . columns ; o ++ ) J . functions [ o ] = c . getColumnData ( d , H . filter _functions , o ) , J . defaultColFilter [ o ] = c . getColumnData ( d , H . filter _defaultFilter , o ) || "" , J . excludeFilter [ o ] = ( c . getColumnData ( d , H . filter _excludeFilter , o , ! 0 ) || "" ) . split ( /\s+/ ) ; for ( G . debug && ( console . log ( "Filter: Starting filter widget search" , e ) , u = new Date ) ,
// filtered rows count
G . filteredRows = 0 , G . totalRows = 0 , f = ( E || [ ] ) . join ( "" ) , m = 0 ; m < G . $tbodies . length ; m ++ ) { if ( n = c . processTbody ( d , G . $tbodies . eq ( m ) , ! 0 ) , o = G . columns , h = G . cache [ m ] . normalized , j = a ( a . map ( h , function ( a ) { return a [ o ] . $row . get ( ) } ) ) , "" === f || H . filter _serversideFiltering ) j . removeClass ( H . filter _filteredRow ) . not ( "." + G . cssChildRow ) . css ( "display" , "" ) ; else { if ( j = j . not ( "." + G . cssChildRow ) , g = j . length , ( H . filter _$anyMatch && H . filter _$anyMatch . length || "undefined" != typeof e [ G . columns ] ) && ( I . anyMatchFlag = ! 0 , I . anyMatchFilter = "" + ( e [ G . columns ] || H . filter _$anyMatch && b . getLatestSearch ( H . filter _$anyMatch ) . val ( ) || "" ) , H . filter _columnAnyMatch ) ) { for ( z = I . anyMatchFilter . split ( F . andSplit ) , A = ! 1 , w = 0 ; w < z . length ; w ++ ) B = z [ w ] . split ( ":" ) , B . length > 1 && ( C = parseInt ( B [ 0 ] , 10 ) - 1 , C >= 0 && C < G . columns && ( e [ C ] = B [ 1 ] , z . splice ( w , 1 ) , w -- , A = ! 0 ) ) ; A && ( I . anyMatchFilter = z . join ( " && " ) ) } if ( y = H . filter _searchFiltered , r = G . lastSearch || G . $table . data ( "lastSearch" ) || [ ] , y )
// cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
for ( w = 0 ; o + 1 > w ; w ++ ) v = e [ w ] || "" , y || ( w = o ) , y = y && r . length && 0 === v . indexOf ( r [ w ] || "" ) && ! F . alreadyFiltered . test ( v ) && ! F . exactTest . test ( v ) && ! ( F . isNeg1 . test ( v ) || F . isNeg2 . test ( v ) ) && ! ( "" !== v && G . $filters && G . $filters . filter ( '[data-column="' + w + '"]' ) . find ( "select" ) . length && ! G . $headerIndexed [ w ] . hasClass ( "filter-match" ) ) ;
// loop through the rows
for ( x = j . not ( "." + H . filter _filteredRow ) . length , y && 0 === x && ( y = ! 1 ) , G . debug && console . log ( "Filter: Searching through " + ( y && g > x ? x : "all" ) + " rows" ) , I . anyMatchFlag && ( G . sortLocaleCompare && ( I . anyMatchFilter = c . replaceAccents ( I . anyMatchFilter ) ) , H . filter _defaultFilter && F . iQuery . test ( J . defaultAnyFilter ) && ( I . anyMatchFilter = b . defaultFilter ( I . anyMatchFilter , J . defaultAnyFilter ) , y = ! 1 ) , I . iAnyMatchFilter = H . filter _ignoreCase && G . ignoreCase ? I . anyMatchFilter . toLowerCase ( ) : I . anyMatchFilter ) , l = 0 ; g > l ; l ++ )
// skip child rows & already filtered rows
if ( D = j [ l ] . className , p = l && F . child . test ( D ) , ! ( p || y && F . filtered . test ( D ) ) ) { if ( I . $row = j . eq ( l ) , I . cacheArray = h [ l ] , i = I . cacheArray [ G . columns ] , I . rawArray = i . raw , I . childRowText = "" , ! H . filter _childByColumn ) {
// 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
for ( D = "" , q = i . child , w = 0 ; w < q . length ; w ++ ) D += " " + q [ w ] . join ( " " ) || "" ; I . childRowText = H . filter _childRows ? H . filter _ignoreCase ? D . toLowerCase ( ) : D : "" } if ( s = ! 1 , t = b . processRow ( G , I , J ) , k = i . $row , v = t ? ! 0 : ! 1 , q = i . $row . filter ( ":gt( 0 )" ) , H . filter _childRows && q . length ) { if ( H . filter _childByColumn )
// cycle through each child row
for ( H . filter _childWithSibs || (
// hide all child rows
q . addClass ( H . filter _filteredRow ) ,
// if only showing resulting child row, only include parent
k = k . eq ( 0 ) ) , w = 0 ; w < q . length ; w ++ ) I . $row = q . eq ( w ) , I . cacheArray = i . child [ w ] , I . rawArray = I . cacheArray , v = b . processRow ( G , I , J ) , s = s || v , ! H . filter _childWithSibs && v && q . eq ( w ) . removeClass ( H . filter _filteredRow ) ;
// keep parent row match even if no child matches... see #1020
s = s || t } else s = v ; k . toggleClass ( H . filter _filteredRow , ! s ) [ 0 ] . display = s ? "" : "none" } } G . filteredRows += j . not ( "." + H . filter _filteredRow ) . length , G . totalRows += j . length , c . processTbody ( d , n , ! 1 ) } G . lastCombinedFilter = f , // save last search
// don't save 'filters' directly since it may have altered ( AnyMatch column searches )
G . lastSearch = E , G . $table . data ( "lastSearch" , E ) , H . filter _saveFilters && c . storage && c . storage ( d , "tablesorter-filters" , b . processFilters ( E , ! 0 ) ) , G . debug && console . log ( "Completed filter widget search" + c . benchmark ( u ) ) , H . filter _initialized && G . $table . trigger ( "filterEnd" , G ) , setTimeout ( function ( ) { c . applyWidget ( G . table ) } , 0 ) } } , getOptionSource : function ( d , e , f ) { d = a ( d ) [ 0 ] ; var g = d . config , h = g . widgetOptions , i = ! 1 , j = h . filter _selectSource , k = g . $table . data ( "lastSearch" ) || [ ] , l = "function" == typeof j ? ! 0 : c . getColumnData ( d , j , e ) ;
// filter select source option
if ( f && "" !== k [ e ] && ( f = ! 1 ) , l === ! 0 )
// OVERALL source
i = j ( d , e , f ) ; else { if ( l instanceof a || "string" === a . type ( l ) && l . indexOf ( "</option>" ) >= 0 )
// selectSource is a jQuery object or string of options
return l ; a . isArray ( l ) ? i = l : "object" === a . type ( j ) && l && (
// custom select source function for a SPECIFIC COLUMN
i = l ( d , e , f ) ) }
// fall back to original method
return i === ! 1 && ( i = b . getOptions ( d , e , f ) ) , b . processOptions ( d , e , i ) } , processOptions : function ( b , d , e ) { if ( ! a . isArray ( e ) ) return ! 1 ; b = a ( b ) [ 0 ] ; var f , g , h , i , j = b . config , k = "undefined" != typeof d && null !== d && d >= 0 && d < j . columns , l = [ ] ; if ( e = a . grep ( e , function ( b , c ) { return a . inArray ( b , e ) === c } ) , k && j . $headerIndexed [ d ] . hasClass ( "filter-select-nosort" ) )
// unsorted select options
return e ;
// parse select option values
for ( i = e . length , h = 0 ; i > h ; h ++ ) g = e [ h ] , l . push ( { t : g , p : k && j . parsers && j . parsers . length && j . parsers [ d ] . format ( g , b , [ ] , d ) || g } ) ; for ( f = j . textSorter || "" , l . sort ( function ( a , e ) { var g = a . p . toString ( ) , h = e . p . toString ( ) ; return k && "function" == typeof f ? f ( g , h , ! 0 , d , b ) : k && "object" == typeof f && f . hasOwnProperty ( d ) ? f [ d ] ( g , h , ! 0 , d , b ) : c . sortNatural ? c . sortNatural ( g , h ) : ! 0 } ) , e = [ ] , i = l . length , h = 0 ; i > h ; h ++ ) e . push ( l [ h ] . t ) ; return e } , getOptions : function ( b , d , e ) { b = a ( b ) [ 0 ] ; var f , g , h , i , j , k , l , m , n = b . config , o = n . widgetOptions , p = [ ] ; for ( g = 0 ; g < n . $tbodies . length ; g ++ )
// loop through the rows
for ( j = n . cache [ g ] , h = n . cache [ g ] . normalized . length , f = 0 ; h > f ; f ++ )
// check if has class filtered
if ( i = j . row ? j . row [ f ] : j . normalized [ f ] [ n . columns ] . $row [ 0 ] , ! e || ! i . className . match ( o . filter _filteredRow ) )
// get non-normalized cell content
if ( o . filter _useParsedData || n . parsers [ d ] . parsed || n . $headerIndexed [ d ] . hasClass ( "filter-parsed" ) ) {
// child row parsed data
if ( p . push ( "" + j . normalized [ f ] [ d ] ) , o . filter _childRows && o . filter _childByColumn ) for ( m = j . normalized [ f ] [ n . columns ] . $row . length - 1 , k = 0 ; m > k ; k ++ ) p . push ( "" + j . normalized [ f ] [ n . columns ] . child [ k ] [ d ] ) } else
// child row unparsed data
if (
// get raw cached data instead of content directly from the cells
p . push ( j . normalized [ f ] [ n . columns ] . raw [ d ] ) , o . filter _childRows && o . filter _childByColumn ) for ( m = j . normalized [ f ] [ n . columns ] . $row . length , k = 1 ; m > k ; k ++ ) l = j . normalized [ f ] [ n . columns ] . $row . eq ( k ) . children ( ) . eq ( d ) , p . push ( "" + c . getElementText ( n , l , d ) ) ; return p } , buildSelect : function ( c , e , f , g , h ) { if ( c = a ( c ) [ 0 ] , e = parseInt ( e , 10 ) , c . config . cache && ! a . isEmptyObject ( c . config . cache ) ) { var i , j , k , l , m , n , o = c . config , p = o . widgetOptions , q = o . $headerIndexed [ e ] ,
// t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
r = '<option value="">' + ( q . data ( "placeholder" ) || q . attr ( "data-placeholder" ) || p . filter _placeholder . select || "" ) + "</option>" ,
// Get curent filter value
s = o . $table . find ( "thead" ) . find ( "select." + d . filter + '[data-column="' + e + '"]' ) . val ( ) ; if (
// nothing included in arry ( external source ), so get the options from
// filter_selectSource or column data
( "undefined" == typeof f || "" === f ) && ( f = b . getOptionSource ( c , e , h ) ) , a . isArray ( f ) ) {
// build option list
for ( i = 0 ; i < f . length ; i ++ ) k = f [ i ] = ( "" + f [ i ] ) . replace ( b . regex . quote , """ ) , j = k , k . indexOf ( p . filter _selectSourceSeparator ) >= 0 && ( l = k . split ( p . filter _selectSourceSeparator ) , j = l [ 0 ] , k = l [ 1 ] ) , r += "" !== f [ i ] ? "<option " + ( j === k ? "" : 'data-function-name="' + f [ i ] + '" ' ) + 'value="' + j + '">' + k + "</option>" : "" ;
// clear arry so it doesn't get appended twice
f = [ ] }
// update all selects in the same column ( clone thead in sticky headers &
// any external selects ) - fixes 473
m = ( o . $filters ? o . $filters : o . $table . children ( "thead" ) ) . find ( "." + d . filter ) , p . filter _$externalFilters && ( m = m && m . length ? m . add ( p . filter _$externalFilters ) : p . filter _$externalFilters ) , n = m . filter ( 'select[data-column="' + e + '"]' ) ,
// make sure there is a select there!
n . length && ( n [ g ? "html" : "append" ] ( r ) , a . isArray ( f ) ||
// append options if arry is provided externally as a string or jQuery object
// options ( default value ) was already added
n . append ( f ) . val ( s ) , n . val ( s ) ) } } , buildDefault : function ( a , d ) { var e , f , g , h = a . config , i = h . widgetOptions , j = h . columns ;
// build default select dropdown
for ( e = 0 ; j > e ; e ++ ) f = h . $headerIndexed [ e ] , g = ! ( f . hasClass ( "filter-false" ) || f . hasClass ( "parser-false" ) ) , ( f . hasClass ( "filter-select" ) || c . getColumnData ( a , i . filter _functions , e ) === ! 0 ) && g && b . buildSelect ( a , e , "" , d , f . hasClass ( i . filter _onlyAvail ) ) } } , c . getFilters = function ( c , e , f , g ) { var h , i , j , k , l = ! 1 , m = c ? a ( c ) [ 0 ] . config : "" , n = m ? m . widgetOptions : "" ; if ( e !== ! 0 && n && ! n . filter _columnFilters || a . isArray ( f ) && f . join ( "" ) === m . lastCombinedFilter ) return a ( c ) . data ( "lastSearch" ) ; if ( m && ( m . $filters && ( i = m . $filters . find ( "." + d . filter ) ) , n . filter _$externalFilters && ( i = i && i . length ? i . add ( n . filter _$externalFilters ) : n . filter _$externalFilters ) , i && i . length ) ) for ( l = f || [ ] , h = 0 ; h < m . columns + 1 ; h ++ ) k = h === m . columns ? n . filter _anyColumnSelector + "," + n . filter _multipleColumnSelector : '[data-column="' + h + '"]' , j = i . filter ( k ) , j . length && ( j = b . getLatestSearch ( j ) , a . isArray ( f ) ? ( g && j . length > 1 && ( j = j . slice ( 1 ) ) , h === m . columns && ( k = j . filter ( n . filter _anyColumnSelector ) , j = k . length ? k : j ) , j . val ( f [ h ] ) . trigger ( "change" + m . namespace ) ) : ( l [ h ] = j . val ( ) || "" , h === m . columns ? j . slice ( 1 ) . filter ( '[data-column*="' + j . attr ( "data-column" ) + '"]' ) . val ( l [ h ] ) : j . slice ( 1 ) . val ( l [ h ] ) ) , h === m . columns && j . length && ( n . filter _$anyMatch = j ) ) ; return 0 === l . length && ( l = ! 1 ) , l } , c . setFilters = function ( d , e , f , g ) { var h = d ? a ( d ) [ 0 ] . config : "" , i = c . getFilters ( d , ! 0 , e , g ) ; return h && f && ( h . lastCombinedFilter = null , h . lastSearch = [ ] , b . searching ( h . table , e , g ) , h . $table . trigger ( "filterFomatterUpdate" ) ) , ! ! i } } ( jQuery ) ;