2015-10-31 15:08:21 +00:00
/ * * * T h i s f i l e i s d y n a m i c a l l y g e n e r a t e d * * *
█ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ ▄ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ █ █ ▄ ▄ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ ▀ ▀ ▀ ▀ █ █
█ █ █ █ █ ▀ ▀ █ █ █ █ ▀ █ █ █ █ ▀ █ █ █ █ ▀ █ █ █ █ █ █ █ █ ▀ █ █ █ █ ▀ █ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ ▀
* /
2015-11-02 16:50:31 +00:00
/*! tablesorter (FORK) - updated 11-02-2015 (v2.24.1)*/
2015-10-31 15:08:21 +00:00
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
! function ( a ) { "function" == typeof define && define . amd ? define ( [ "jquery" ] , a ) : "object" == typeof module && "object" == typeof module . exports ? module . exports = a ( require ( "jquery" ) ) : a ( jQuery ) } ( function ( a ) { return function ( a , b , c ) { "use strict" ; var d = a . tablesorter || { } ;
// *** Store data in local storage, with a cookie fallback ***
/* IE7 needs JSON library for JSON.stringify - (http:/ / caniuse . com / # search = json )
if you need it , then include https : //github.com/douglascrockford/JSON-js
$ . parseJSON is not available is jQuery versions older than 1.4 . 1 , using older
versions will only allow storing information for one page at a time
// *** Save data (JSON format only) ***
// val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
var val = { "mywidget" : "data1" } ; // valid JSON uses double quotes
// $.tablesorter.storage(table, key, val);
$ . tablesorter . storage ( table , 'tablesorter-mywidget' , val ) ;
// *** Get data: $.tablesorter.storage(table, key); ***
v = $ . tablesorter . storage ( table , 'tablesorter-mywidget' ) ;
// val may be empty, so also check for your data
val = ( v && v . hasOwnProperty ( 'mywidget' ) ) ? v . mywidget : '' ;
alert ( val ) ; // 'data1' if saved, or '' if not
* /
d . storage = function ( d , e , f , g ) { d = a ( d ) [ 0 ] ; var h , i , j , k = ! 1 , l = { } , m = d . config , n = m && m . widgetOptions , o = g && g . useSessionStorage || n && n . storage _useSessionStorage ? "sessionStorage" : "localStorage" , p = a ( d ) ,
// id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
// (4) table ID, then (5) table index
q = g && g . id || p . attr ( g && g . group || n && n . storage _group || "data-table-group" ) || n && n . storage _tableId || d . id || a ( ".tablesorter" ) . index ( p ) ,
// url from (1) options url, (2) table 'data-table-page' attribute, (3) widgetOptions.storage_fixedUrl,
// (4) table.config.fixedUrl (deprecated), then (5) window location path
r = g && g . url || p . attr ( g && g . page || n && n . storage _page || "data-table-page" ) || n && n . storage _fixedUrl || m && m . fixedUrl || b . location . pathname ;
// https://gist.github.com/paulirish/5558557
if ( o in b ) try { b [ o ] . setItem ( "_tmptest" , "temp" ) , k = ! 0 , b [ o ] . removeItem ( "_tmptest" ) } catch ( s ) { m && m . debug && console . warn ( o + " is not supported in this browser" ) }
// allow value to be an empty string too
// *** get value ***
// old browser, using cookies
// add one to get from the key to the value
// allow value to be an empty string too
// add unique identifiers = url pathname > table ID/index on page > data
// *** set value ***
// 365 days
return a . parseJSON && ( k ? l = a . parseJSON ( b [ o ] [ e ] || "null" ) || { } : ( i = c . cookie . split ( /[;\s|=]/ ) , h = a . inArray ( e , i ) + 1 , l = 0 !== h ? a . parseJSON ( i [ h ] || "null" ) || { } : { } ) ) , ( f || "" === f ) && b . JSON && JSON . hasOwnProperty ( "stringify" ) ? ( l [ r ] || ( l [ r ] = { } ) , l [ r ] [ q ] = f , k ? b [ o ] [ e ] = JSON . stringify ( l ) : ( j = new Date , j . setTime ( j . getTime ( ) + 31536e6 ) , c . cookie = e + "=" + JSON . stringify ( l ) . replace ( /\"/g , '"' ) + "; expires=" + j . toGMTString ( ) + "; path=/" ) , void 0 ) : l && l [ r ] ? l [ r ] [ q ] : "" } } ( jQuery , window , document ) , function ( a ) { "use strict" ; var b = a . tablesorter || { } ; b . themes = { bootstrap : { table : "table table-bordered table-striped" , caption : "caption" ,
// header class names
header : "bootstrap-header" , // give the header a gradient background (theme.bootstrap_2.css)
sortNone : "" , sortAsc : "" , sortDesc : "" , active : "" , // applied when column is sorted
hover : "" , // custom css required - a defined bootstrap style may not override other classes
// icon class names
icons : "" , // add 'icon-white' to make them white; this icon class is added to the <i> in the header
iconSortNone : "bootstrap-icon-unsorted" , // class name added to icon when column is not sorted
iconSortAsc : "icon-chevron-up glyphicon glyphicon-chevron-up" , // class name added to icon when column has ascending sort
iconSortDesc : "icon-chevron-down glyphicon glyphicon-chevron-down" , // class name added to icon when column has descending sort
filterRow : "" , // filter row class
footerRow : "" , footerCells : "" , even : "" , // even row zebra striping
odd : "" } , jui : { table : "ui-widget ui-widget-content ui-corner-all" , // table classes
caption : "ui-widget-content" ,
// header class names
header : "ui-widget-header ui-corner-all ui-state-default" , // header classes
sortNone : "" , sortAsc : "" , sortDesc : "" , active : "ui-state-active" , // applied when column is sorted
hover : "ui-state-hover" , // hover class
// icon class names
icons : "ui-icon" , // icon class added to the <i> in the header
iconSortNone : "ui-icon-carat-2-n-s" , // class name added to icon when column is not sorted
iconSortAsc : "ui-icon-carat-1-n" , // class name added to icon when column has ascending sort
iconSortDesc : "ui-icon-carat-1-s" , // class name added to icon when column has descending sort
filterRow : "" , footerRow : "" , footerCells : "" , even : "ui-widget-content" , // even row zebra striping
odd : "ui-state-default" } } , a . extend ( b . css , { wrapper : "tablesorter-wrapper" } ) , b . addWidget ( { id : "uitheme" , priority : 10 , format : function ( c , d , e ) { var f , g , h , i , j , k , l , m , n , o , p , q , r = b . themes , s = d . $table . add ( a ( d . namespace + "_extra_table" ) ) , t = d . $headers . add ( a ( d . namespace + "_extra_headers" ) ) , u = d . theme || "jui" , v = r [ u ] || { } , w = a . trim ( [ v . sortNone , v . sortDesc , v . sortAsc , v . active ] . join ( " " ) ) , x = a . trim ( [ v . iconSortNone , v . iconSortDesc , v . iconSortAsc ] . join ( " " ) ) ; for ( d . debug && ( i = new Date ) ,
// initialization code - run once
s . hasClass ( "tablesorter-" + u ) && d . theme === d . appliedTheme && e . uitheme _applied || ( e . uitheme _applied = ! 0 , n = r [ d . appliedTheme ] || { } , q = ! a . isEmptyObject ( n ) , o = q ? [ n . sortNone , n . sortDesc , n . sortAsc , n . active ] . join ( " " ) : "" , p = q ? [ n . iconSortNone , n . iconSortDesc , n . iconSortAsc ] . join ( " " ) : "" , q && ( e . zebra [ 0 ] = a . trim ( " " + e . zebra [ 0 ] . replace ( " " + n . even , "" ) ) , e . zebra [ 1 ] = a . trim ( " " + e . zebra [ 1 ] . replace ( " " + n . odd , "" ) ) , d . $tbodies . children ( ) . removeClass ( [ n . even , n . odd ] . join ( " " ) ) ) , v . even && ( e . zebra [ 0 ] += " " + v . even ) , v . odd && ( e . zebra [ 1 ] += " " + v . odd ) , s . children ( "caption" ) . removeClass ( n . caption || "" ) . addClass ( v . caption ) , l = s . removeClass ( ( d . appliedTheme ? "tablesorter-" + ( d . appliedTheme || "" ) : "" ) + " " + ( n . table || "" ) ) . addClass ( "tablesorter-" + u + " " + ( v . table || "" ) ) . children ( "tfoot" ) , d . appliedTheme = d . theme , l . length && l . children ( "tr" ) . removeClass ( n . footerRow || "" ) . addClass ( v . footerRow ) . children ( "th, td" ) . removeClass ( n . footerCells || "" ) . addClass ( v . footerCells ) , t . removeClass ( ( q ? [ n . header , n . hover , o ] . join ( " " ) : "" ) || "" ) . addClass ( v . header ) . not ( ".sorter-false" ) . unbind ( "mouseenter.tsuitheme mouseleave.tsuitheme" ) . bind ( "mouseenter.tsuitheme mouseleave.tsuitheme" , function ( b ) { a ( this ) [ "mouseenter" === b . type ? "addClass" : "removeClass" ] ( v . hover || "" ) } ) , t . each ( function ( ) { var c = a ( this ) ; c . find ( "." + b . css . wrapper ) . length || c . wrapInner ( '<div class="' + b . css . wrapper + '" style="position:relative;height:100%;width:100%"></div>' ) } ) , d . cssIcon && t . find ( "." + b . css . icon ) . removeClass ( q ? [ n . icons , p ] . join ( " " ) : "" ) . addClass ( v . icons || "" ) , s . hasClass ( "hasFilters" ) && s . children ( "thead" ) . children ( "." + b . css . filterRow ) . removeClass ( q ? n . filterRow || "" : "" ) . addClass ( v . filterRow || "" ) ) , f = 0 ; f < d . columns ; f ++ ) j = d . $headers . add ( a ( d . namespace + "_extra_headers" ) ) . not ( ".sorter-false" ) . filter ( '[data-column="' + f + '"]' ) , k = b . css . icon ? j . find ( "." + b . css . icon ) : a ( ) , m = t . not ( ".sorter-false" ) . filter ( '[data-column="' + f + '"]:last' ) , m . length && ( j . removeClass ( w ) , k . removeClass ( x ) , m [ 0 ] . sortDisabled ? k . removeClass ( v . icons || "" ) : ( g = v . sortNone , h = v . iconSortNone , m . hasClass ( b . css . sortAsc ) ? ( g = [ v . sortAsc , v . active ] . join ( " " ) , h = v . iconSortAsc ) : m . hasClass ( b . css . sortDesc ) && ( g = [ v . sortDesc , v . active ] . join ( " " ) , h = v . iconSortDesc ) , j . addClass ( g ) , k . addClass ( h || "" ) ) ) ; d . debug && console . log ( "Applying " + u + " theme" + b . benchmark ( i ) ) } , remove : function ( a , c , d , e ) { if ( d . uitheme _applied ) { var f = c . $table , g = c . appliedTheme || "jui" , h = b . themes [ g ] || b . themes . jui , i = f . children ( "thead" ) . children ( ) , j = h . sortNone + " " + h . sortDesc + " " + h . sortAsc , k = h . iconSortNone + " " + h . iconSortDesc + " " + h . iconSortAsc ; f . removeClass ( "tablesorter-" + g + " " + h . table ) , d . uitheme _applied = ! 1 , e || ( f . find ( b . css . header ) . removeClass ( h . header ) , i . unbind ( "mouseenter.tsuitheme mouseleave.tsuitheme" ) . removeClass ( h . hover + " " + j + " " + h . active ) . filter ( "." + b . css . filterRow ) . removeClass ( h . filterRow ) , i . find ( "." + b . css . icon ) . removeClass ( h . icons + " " + k ) ) } } } ) } ( jQuery ) , function ( a ) { "use strict" ; var b = a . tablesorter || { } ; b . addWidget ( { id : "columns" , priority : 30 , options : { columns : [ "primary" , "secondary" , "tertiary" ] } , format : function ( c , d , e ) { var f , g , h , i , j , k , l , m , n = d . $table , o = d . $tbodies , p = d . sortList , q = p . length ,
// removed c.widgetColumns support
r = e && e . columns || [ "primary" , "secondary" , "tertiary" ] , s = r . length - 1 ;
// check if there is a sort (on initialization there may not be one)
for ( l = r . join ( " " ) , g = 0 ; g < o . length ; g ++ ) f = b . processTbody ( c , o . eq ( g ) , ! 0 ) , h = f . children ( "tr" ) , h . each ( function ( ) { if ( j = a ( this ) , "none" !== this . style . display && ( k = j . children ( ) . removeClass ( l ) , p && p [ 0 ] && ( k . eq ( p [ 0 ] [ 0 ] ) . addClass ( r [ 0 ] ) , q > 1 ) ) ) for ( m = 1 ; q > m ; m ++ ) k . eq ( p [ m ] [ 0 ] ) . addClass ( r [ m ] || r [ s ] ) } ) , b . processTbody ( c , f , ! 1 ) ; if ( i = e . columns _thead !== ! 1 ? [ "thead tr" ] : [ ] , e . columns _tfoot !== ! 1 && i . push ( "tfoot tr" ) , i . length && ( h = n . find ( i . join ( "," ) ) . children ( ) . removeClass ( l ) , q ) ) for ( m = 0 ; q > m ; m ++ )
// add primary. secondary, tertiary, etc sort column classes
h . filter ( '[data-column="' + p [ m ] [ 0 ] + '"]' ) . addClass ( r [ m ] || r [ s ] ) } , remove : function ( c , d , e ) { var f , g , h = d . $tbodies , i = ( e . columns || [ "primary" , "secondary" , "tertiary" ] ) . join ( " " ) ; for ( d . $headers . removeClass ( i ) , d . $table . children ( "tfoot" ) . children ( "tr" ) . children ( "th, td" ) . removeClass ( i ) , f = 0 ; f < h . length ; f ++ ) g = b . processTbody ( c , h . eq ( f ) , ! 0 ) , g . children ( "tr" ) . each ( function ( ) { a ( this ) . children ( ) . removeClass ( i ) } ) , b . processTbody ( c , g , ! 1 ) } } ) } ( jQuery ) , 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 ) , function ( a , b ) { "use strict" ; var c = a . tablesorter || { } ; a . extend ( c . css , { sticky : "tablesorter-stickyHeader" , // stickyHeader
stickyVis : "tablesorter-sticky-visible" , stickyHide : "tablesorter-sticky-hidden" , stickyWrap : "tablesorter-sticky-wrapper" } ) ,
// Add a resize event to table headers
c . addHeaderResizeEvent = function ( b , c , d ) { // make sure we're using a dom element
if ( b = a ( b ) [ 0 ] , b . config ) { var e = { timer : 250 } , f = a . extend ( { } , e , d ) , g = b . config , h = g . widgetOptions , i = function ( a ) { var b , c , d , e , f , i , j = g . $headers . length ; for ( h . resize _flag = ! 0 , c = [ ] , b = 0 ; j > b ; b ++ ) d = g . $headers . eq ( b ) , e = d . data ( "savedSizes" ) || [ 0 , 0 ] , f = d [ 0 ] . offsetWidth , i = d [ 0 ] . offsetHeight , ( f !== e [ 0 ] || i !== e [ 1 ] ) && ( d . data ( "savedSizes" , [ f , i ] ) , c . push ( d [ 0 ] ) ) ; c . length && a !== ! 1 && g . $table . trigger ( "resize" , [ c ] ) , h . resize _flag = ! 1 } ; return i ( ! 1 ) , clearInterval ( h . resize _timer ) , c ? ( h . resize _flag = ! 1 , ! 1 ) : void ( h . resize _timer = setInterval ( function ( ) { h . resize _flag || i ( ) } , f . timer ) ) } } ,
// Sticky headers based on this awesome article:
// http://css-tricks.com/13465-persistent-headers/
// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
// **************************
c . addWidget ( { id : "stickyHeaders" , priority : 60 , // sticky widget must be initialized after the filter widget!
options : { stickyHeaders : "" , // extra class name added to the sticky header row
stickyHeaders _attachTo : null , // jQuery selector or object to attach sticky header to
stickyHeaders _xScroll : null , // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders _yScroll : null , // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders _offset : 0 , // number or jquery selector targeting the position:fixed element
stickyHeaders _filteredToTop : ! 0 , // scroll table top into view after filtering
stickyHeaders _cloneId : "-sticky" , // added to table ID, if it exists
stickyHeaders _addResizeEvent : ! 0 , // trigger 'resize' event on headers
stickyHeaders _includeCaption : ! 0 , // if false and a caption exist, it won't be included in the sticky header
stickyHeaders _zIndex : 2 } , format : function ( d , e , f ) {
// filter widget doesn't initialize on an empty table. Fixes #449
if ( ! ( e . $table . hasClass ( "hasStickyHeaders" ) || a . inArray ( "filter" , e . widgets ) >= 0 && ! e . $table . hasClass ( "hasFilters" ) ) ) { var g , h , i , j , k = e . $table ,
// add position: relative to attach element, hopefully it won't cause trouble.
l = a ( f . stickyHeaders _attachTo ) , m = e . namespace + "stickyheaders " ,
// element to watch for the scroll event
n = a ( f . stickyHeaders _yScroll || f . stickyHeaders _attachTo || b ) , o = a ( f . stickyHeaders _xScroll || f . stickyHeaders _attachTo || b ) , p = k . children ( "thead:first" ) , q = p . children ( "tr" ) . not ( ".sticky-false" ) . children ( ) , r = k . children ( "tfoot" ) , s = isNaN ( f . stickyHeaders _offset ) ? a ( f . stickyHeaders _offset ) : "" , t = s . length ? s . height ( ) || 0 : parseInt ( f . stickyHeaders _offset , 10 ) || 0 ,
// is this table nested? If so, find parent sticky header wrapper (div, not table)
u = k . parent ( ) . closest ( "." + c . css . table ) . hasClass ( "hasStickyHeaders" ) ? k . parent ( ) . closest ( "table.tablesorter" ) [ 0 ] . config . widgetOptions . $sticky . parent ( ) : [ ] , v = u . length ? u . height ( ) : 0 ,
// clone table, then wrap to make sticky header
w = f . $sticky = k . clone ( ) . addClass ( "containsStickyHeaders " + c . css . sticky + " " + f . stickyHeaders + " " + e . namespace . slice ( 1 ) + "_extra_table" ) . wrap ( '<div class="' + c . css . stickyWrap + '">' ) , x = w . parent ( ) . addClass ( c . css . stickyHide ) . css ( { position : l . length ? "absolute" : "fixed" , padding : parseInt ( w . parent ( ) . parent ( ) . css ( "padding-left" ) , 10 ) , top : t + v , left : 0 , visibility : "hidden" , zIndex : f . stickyHeaders _zIndex || 2 } ) , y = w . children ( "thead:first" ) , z = "" , A = 0 , B = function ( a , c ) { var d , e , f , g , h , i = a . filter ( ":visible" ) , j = i . length ; for ( d = 0 ; j > d ; d ++ ) g = c . filter ( ":visible" ) . eq ( d ) , h = i . eq ( d ) , "border-box" === h . css ( "box-sizing" ) ? e = h . outerWidth ( ) : "collapse" === g . css ( "border-collapse" ) ? b . getComputedStyle ? e = parseFloat ( b . getComputedStyle ( h [ 0 ] , null ) . width ) : ( f = parseFloat ( h . css ( "border-width" ) ) , e = h . outerWidth ( ) - parseFloat ( h . css ( "padding-left" ) ) - parseFloat ( h . css ( "padding-right" ) ) - f ) : e = h . width ( ) , g . css ( { width : e , "min-width" : e , "max-width" : e } ) } , C = function ( ) { t = s . length ? s . height ( ) || 0 : parseInt ( f . stickyHeaders _offset , 10 ) || 0 , A = 0 , x . css ( { left : l . length ? parseInt ( l . css ( "padding-left" ) , 10 ) || 0 : k . offset ( ) . left - parseInt ( k . css ( "margin-left" ) , 10 ) - o . scrollLeft ( ) - A , width : k . outerWidth ( ) } ) , B ( k , w ) , B ( q , j ) } , D = function ( b ) { if ( k . is ( ":visible" ) ) { // fixes #278
// Detect nested tables - fixes #724
v = u . length ? u . offset ( ) . top - n . scrollTop ( ) + u . height ( ) : 0 ; var d = k . offset ( ) , e = a . isWindow ( n [ 0 ] ) , // $.isWindow needs jQuery 1.4.3
f = a . isWindow ( o [ 0 ] ) ,
// scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
g = ( l . length ? e ? n . scrollTop ( ) : n . offset ( ) . top : n . scrollTop ( ) ) + t + v , h = k . height ( ) - ( x . height ( ) + ( r . height ( ) || 0 ) ) , i = g > d . top && g < d . top + h ? "visible" : "hidden" , j = { visibility : i } ; l . length && ( j . top = e ? g - l . offset ( ) . top : l . scrollTop ( ) ) , f && (
// adjust when scrolling horizontally - fixes issue #143
j . left = k . offset ( ) . left - parseInt ( k . css ( "margin-left" ) , 10 ) - o . scrollLeft ( ) - A ) , u . length && ( j . top = ( j . top || 0 ) + t + v ) , x . removeClass ( c . css . stickyVis + " " + c . css . stickyHide ) . addClass ( "visible" === i ? c . css . stickyVis : c . css . stickyHide ) . css ( j ) , ( i !== z || b ) && (
// make sure the column widths match
C ( ) , z = i ) } } ;
// onRenderHeader is defined, we need to do something about it (fixes #641)
if (
// only add a position relative if a position isn't already defined
l . length && ! l . css ( "position" ) && l . css ( "position" , "relative" ) ,
// fix clone ID, if it exists - fixes #271
w . attr ( "id" ) && ( w [ 0 ] . id += f . stickyHeaders _cloneId ) ,
// clear out cloned table, except for sticky header
// include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing
w . find ( "thead:gt(0), tr.sticky-false" ) . hide ( ) , w . find ( "tbody, tfoot" ) . remove ( ) , w . find ( "caption" ) . toggle ( f . stickyHeaders _includeCaption ) , j = y . children ( ) . children ( ) , w . css ( { height : 0 , width : 0 , margin : 0 } ) , j . find ( "." + c . css . resizer ) . remove ( ) , k . addClass ( "hasStickyHeaders" ) . bind ( "pagerComplete" + m , function ( ) { C ( ) } ) , c . bindEvents ( d , y . children ( ) . children ( "." + c . css . header ) ) , k . after ( x ) , e . onRenderHeader ) for ( i = y . children ( "tr" ) . children ( ) , h = i . length , g = 0 ; h > g ; g ++ )
// send second parameter
e . onRenderHeader . apply ( i . eq ( g ) , [ g , e , w ] ) ;
// make it sticky!
o . add ( n ) . unbind ( "scroll resize " . split ( " " ) . join ( m ) . replace ( /\s+/g , " " ) ) . bind ( "scroll resize " . split ( " " ) . join ( m ) , function ( a ) { D ( "resize" === a . type ) } ) , e . $table . unbind ( "stickyHeadersUpdate" + m ) . bind ( "stickyHeadersUpdate" + m , function ( ) { D ( ! 0 ) } ) , f . stickyHeaders _addResizeEvent && c . addHeaderResizeEvent ( d ) ,
// look for filter widget
k . hasClass ( "hasFilters" ) && f . filter _columnFilters && (
// scroll table into view after filtering, if sticky header is active - #482
k . bind ( "filterEnd" + m , function ( ) {
// $(':focus') needs jQuery 1.6+
var d = a ( document . activeElement ) . closest ( "td" ) , g = d . parent ( ) . children ( ) . index ( d ) ;
// only scroll if sticky header is active
x . hasClass ( c . css . stickyVis ) && f . stickyHeaders _filteredToTop && (
// scroll to original table (not sticky clone)
b . scrollTo ( 0 , k . position ( ) . top ) ,
// give same input/select focus; check if c.$filters exists; fixes #594
g >= 0 && e . $filters && e . $filters . eq ( g ) . find ( "a, select, input" ) . filter ( ":visible" ) . focus ( ) ) } ) , c . filter . bindSearch ( k , j . find ( "." + c . css . filter ) ) ,
// support hideFilters
f . filter _hideFilters && c . filter . hideFilters ( e , w ) ) , k . trigger ( "stickyHeadersInit" ) } } , remove : function ( d , e , f ) { var g = e . namespace + "stickyheaders " ; e . $table . removeClass ( "hasStickyHeaders" ) . unbind ( "pagerComplete filterEnd stickyHeadersUpdate " . split ( " " ) . join ( g ) . replace ( /\s+/g , " " ) ) . next ( "." + c . css . stickyWrap ) . remove ( ) , f . $sticky && f . $sticky . length && f . $sticky . remove ( ) , // remove cloned table
a ( b ) . add ( f . stickyHeaders _xScroll ) . add ( f . stickyHeaders _yScroll ) . add ( f . stickyHeaders _attachTo ) . unbind ( "scroll resize " . split ( " " ) . join ( g ) . replace ( /\s+/g , " " ) ) , c . addHeaderResizeEvent ( d , ! 1 ) } } ) } ( jQuery , window ) , function ( a , b ) { "use strict" ; var c = a . tablesorter || { } ; a . extend ( c . css , { resizableContainer : "tablesorter-resizable-container" , resizableHandle : "tablesorter-resizable-handle" , resizableNoSelect : "tablesorter-disableSelection" , resizableStorage : "tablesorter-resizable" } ) ,
// Add extra scroller css
a ( function ( ) { var b = "<style>body." + c . css . resizableNoSelect + " { -ms-user-select: none; -moz-user-select: -moz-none;-khtml-user-select: none; -webkit-user-select: none; user-select: none; }." + c . css . resizableContainer + " { position: relative; height: 1px; }." + c . css . resizableHandle + " { position: absolute; display: inline-block; width: 8px;top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }</style>" ; a ( b ) . appendTo ( "body" ) } ) , c . resizable = { init : function ( b , d ) { if ( ! b . $table . hasClass ( "hasResizable" ) ) { b . $table . addClass ( "hasResizable" ) ; var e , f , g , h , i , j = b . $table , k = j . parent ( ) , l = parseInt ( j . css ( "margin-top" ) , 10 ) ,
// internal variables
m = d . resizable _vars = { useStorage : c . storage && d . resizable !== ! 1 , $wrap : k , mouseXPosition : 0 , $target : null , $next : null , overflow : "auto" === k . css ( "overflow" ) || "scroll" === k . css ( "overflow" ) || "auto" === k . css ( "overflow-x" ) || "scroll" === k . css ( "overflow-x" ) , storedSizes : [ ] } ;
// add container
for (
// set default widths
c . resizableReset ( b . table , ! 0 ) ,
// now get measurements!
m . tableWidth = j . width ( ) ,
// attempt to autodetect
m . fullWidth = Math . abs ( k . width ( ) - m . tableWidth ) < 20 , / *
// Hacky method to determine if table width is set to 'auto'
// http://stackoverflow.com/a/20892048/145346
if ( ! vars . fullWidth ) {
tmp = $table . width ( ) ;
$header = $table . wrap ( '<span>' ) . parent ( ) ; // temp variable
storedSizes = parseInt ( $table . css ( 'margin-left' ) , 10 ) || 0 ;
$table . css ( 'margin-left' , storedSizes + 50 ) ;
vars . tableWidth = $header . width ( ) > tmp ? 'auto' : tmp ;
$table . css ( 'margin-left' , storedSizes ? storedSizes : '' ) ;
$header = null ;
$table . unwrap ( '<span>' ) ;
}
* /
m . useStorage && m . overflow && (
// save table width
c . storage ( b . table , "tablesorter-table-original-css-width" , m . tableWidth ) , i = c . storage ( b . table , "tablesorter-table-resized-width" ) || "auto" , c . resizable . setWidth ( j , i , ! 0 ) ) , d . resizable _vars . storedSizes = h = ( m . useStorage ? c . storage ( b . table , c . css . resizableStorage ) : [ ] ) || [ ] , c . resizable . setWidths ( b , d , h ) , c . resizable . updateStoredSizes ( b , d ) , d . $resizable _container = a ( '<div class="' + c . css . resizableContainer + '">' ) . css ( { top : l } ) . insertBefore ( j ) , g = 0 ; g < b . columns ; g ++ ) f = b . $headerIndexed [ g ] , i = c . getColumnData ( b . table , b . headers , g ) , e = "false" === c . getData ( f , i , "resizable" ) , e || a ( '<div class="' + c . css . resizableHandle + '">' ) . appendTo ( d . $resizable _container ) . attr ( { "data-column" : g , unselectable : "on" } ) . data ( "header" , f ) . bind ( "selectstart" , ! 1 ) ; j . one ( "tablesorter-initialized" , function ( ) { c . resizable . setHandlePosition ( b , d ) , c . resizable . bindings ( this . config , this . config . widgetOptions ) } ) } } , updateStoredSizes : function ( a , b ) { var c , d , e = a . columns , f = b . resizable _vars ; for ( f . storedSizes = [ ] , c = 0 ; e > c ; c ++ ) d = a . $headerIndexed [ c ] , f . storedSizes [ c ] = d . is ( ":visible" ) ? d . width ( ) : 0 } , setWidth : function ( a , b , c ) {
// overflow tables need min & max width set as well
a . css ( { width : b , "min-width" : c ? b : "" , "max-width" : c ? b : "" } ) } , setWidths : function ( b , d , e ) { var f , g , h = d . resizable _vars , i = a ( b . namespace + "_extra_headers" ) , j = b . $table . children ( "colgroup" ) . children ( "col" ) ;
// process only if table ID or url match
if ( e = e || h . storedSizes || [ ] , e . length ) { for ( f = 0 ; f < b . columns ; f ++ )
// set saved resizable widths
c . resizable . setWidth ( b . $headerIndexed [ f ] , e [ f ] , h . overflow ) , i . length && ( g = i . eq ( f ) . add ( j . eq ( f ) ) , c . resizable . setWidth ( g , e [ f ] , h . overflow ) ) ; g = a ( b . namespace + "_extra_table" ) , g . length && ! c . hasWidget ( b . table , "scroller" ) && c . resizable . setWidth ( g , b . $table . outerWidth ( ) , h . overflow ) } } , setHandlePosition : function ( b , d ) { var e , f = c . hasWidget ( b . table , "scroller" ) , g = b . $table . height ( ) , h = d . $resizable _container . children ( ) , i = Math . floor ( h . width ( ) / 2 ) ; f && ( g = 0 , b . $table . closest ( "." + c . css . scrollerWrap ) . children ( ) . each ( function ( ) { var b = a ( this ) ; g += b . filter ( '[style*="height"]' ) . length ? b . height ( ) : b . children ( "table" ) . height ( ) } ) ) , e = b . $table . position ( ) . left , h . each ( function ( ) { var c = a ( this ) , f = parseInt ( c . attr ( "data-column" ) , 10 ) , h = b . columns - 1 , j = c . data ( "header" ) ; j && ( j . is ( ":visible" ) ? ( h > f || f === h && d . resizable _addLastColumn ) && c . css ( { display : "inline-block" , height : g , left : j . position ( ) . left - e + j . outerWidth ( ) - i } ) : c . hide ( ) ) } ) } ,
// prevent text selection while dragging resize bar
toggleTextSelection : function ( b , d ) { var e = b . namespace + "tsresize" ; b . widgetOptions . resizable _vars . disabled = d , a ( "body" ) . toggleClass ( c . css . resizableNoSelect , d ) , d ? a ( "body" ) . attr ( "unselectable" , "on" ) . bind ( "selectstart" + e , ! 1 ) : a ( "body" ) . removeAttr ( "unselectable" ) . unbind ( "selectstart" + e ) } , bindings : function ( d , e ) { var f = d . namespace + "tsresize" ; e . $resizable _container . children ( ) . bind ( "mousedown" , function ( b ) {
// save header cell and mouse position
var f , g = e . resizable _vars , h = a ( d . namespace + "_extra_headers" ) , i = a ( b . target ) . data ( "header" ) ; f = parseInt ( i . attr ( "data-column" ) , 10 ) , g . $target = i = i . add ( h . filter ( '[data-column="' + f + '"]' ) ) , g . target = f , g . $next = b . shiftKey || e . resizable _targetLast ? i . parent ( ) . children ( ) . not ( ".resizable-false" ) . filter ( ":last" ) : i . nextAll ( ":not(.resizable-false)" ) . eq ( 0 ) , f = parseInt ( g . $next . attr ( "data-column" ) , 10 ) , g . $next = g . $next . add ( h . filter ( '[data-column="' + f + '"]' ) ) , g . next = f , g . mouseXPosition = b . pageX , c . resizable . updateStoredSizes ( d , e ) , c . resizable . toggleTextSelection ( d , ! 0 ) } ) , a ( document ) . bind ( "mousemove" + f , function ( a ) { var b = e . resizable _vars ;
// ignore mousemove if no mousedown
b . disabled && 0 !== b . mouseXPosition && b . $target && ( e . resizable _throttle ? ( clearTimeout ( b . timer ) , b . timer = setTimeout ( function ( ) { c . resizable . mouseMove ( d , e , a ) } , isNaN ( e . resizable _throttle ) ? 5 : e . resizable _throttle ) ) : c . resizable . mouseMove ( d , e , a ) ) } ) . bind ( "mouseup" + f , function ( ) { e . resizable _vars . disabled && ( c . resizable . toggleTextSelection ( d , ! 1 ) , c . resizable . stopResize ( d , e ) , c . resizable . setHandlePosition ( d , e ) ) } ) ,
// resizeEnd event triggered by scroller widget
a ( b ) . bind ( "resize" + f + " resizeEnd" + f , function ( ) { c . resizable . setHandlePosition ( d , e ) } ) ,
// right click to reset columns to default widths
d . $table . bind ( "columnUpdate" + f , function ( ) { c . resizable . setHandlePosition ( d , e ) } ) . find ( "thead:first" ) . add ( a ( d . namespace + "_extra_table" ) . find ( "thead:first" ) ) . bind ( "contextmenu" + f , function ( ) {
// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
var a = 0 === e . resizable _vars . storedSizes . length ; return c . resizableReset ( d . table ) , c . resizable . setHandlePosition ( d , e ) , e . resizable _vars . storedSizes = [ ] , a } ) } , mouseMove : function ( b , d , e ) { if ( 0 !== d . resizable _vars . mouseXPosition && d . resizable _vars . $target ) {
// resize columns
var f , g = 0 , h = d . resizable _vars , i = h . $next , j = h . storedSizes [ h . target ] , k = e . pageX - h . mouseXPosition ; if ( h . overflow ) { if ( j + k > 0 ) {
// update the entire table width
for ( h . storedSizes [ h . target ] += k , c . resizable . setWidth ( h . $target , h . storedSizes [ h . target ] , ! 0 ) , f = 0 ; f < b . columns ; f ++ ) g += h . storedSizes [ f ] ; c . resizable . setWidth ( b . $table . add ( a ( b . namespace + "_extra_table" ) ) , g ) } i . length || (
// if expanding right-most column, scroll the wrapper
h . $wrap [ 0 ] . scrollLeft = b . $table . width ( ) ) } else h . fullWidth ? ( h . storedSizes [ h . target ] += k , h . storedSizes [ h . next ] -= k , c . resizable . setWidths ( b , d ) ) : ( h . storedSizes [ h . target ] += k , c . resizable . setWidths ( b , d ) ) ; h . mouseXPosition = e . pageX ,
// dynamically update sticky header widths
b . $table . trigger ( "stickyHeadersUpdate" ) } } , stopResize : function ( a , b ) { var d = b . resizable _vars ; c . resizable . updateStoredSizes ( a , b ) , d . useStorage && (
// save all column widths
c . storage ( a . table , c . css . resizableStorage , d . storedSizes ) , c . storage ( a . table , "tablesorter-table-resized-width" , a . $table . width ( ) ) ) , d . mouseXPosition = 0 , d . $target = d . $next = null ,
// will update stickyHeaders, just in case, see #912
a . $table . trigger ( "stickyHeadersUpdate" ) } } ,
// this widget saves the column widths if
// $.tablesorter.storage function is included
// **************************
c . addWidget ( { id : "resizable" , priority : 40 , options : { resizable : ! 0 , // save column widths to storage
resizable _addLastColumn : ! 1 , resizable _widths : [ ] , resizable _throttle : ! 1 , // set to true (5ms) or any number 0-10 range
resizable _targetLast : ! 1 , resizable _fullWidth : null } , init : function ( a , b , d , e ) { c . resizable . init ( d , e ) } , remove : function ( b , d , e , f ) { if ( e . $resizable _container ) { var g = d . namespace + "tsresize" ; d . $table . add ( a ( d . namespace + "_extra_table" ) ) . removeClass ( "hasResizable" ) . children ( "thead" ) . unbind ( "contextmenu" + g ) , e . $resizable _container . remove ( ) , c . resizable . toggleTextSelection ( d , ! 1 ) , c . resizableReset ( b , f ) , a ( document ) . unbind ( "mousemove" + g + " mouseup" + g ) } } } ) , c . resizableReset = function ( b , d ) { a ( b ) . each ( function ( ) { var a , e , f = this . config , g = f && f . widgetOptions , h = g . resizable _vars ; if ( b && f && f . $headerIndexed . length ) { for (
// restore the initial table width
h . overflow && h . tableWidth && ( c . resizable . setWidth ( f . $table , h . tableWidth , ! 0 ) , h . useStorage && c . storage ( b , "tablesorter-table-resized-width" , "auto" ) ) , a = 0 ; a < f . columns ; a ++ ) e = f . $headerIndexed [ a ] , g . resizable _widths && g . resizable _widths [ a ] ? c . resizable . setWidth ( e , g . resizable _widths [ a ] , h . overflow ) : e . hasClass ( "resizable-false" ) || c . resizable . setWidth ( e , "" , h . overflow ) ;
// reset stickyHeader widths
f . $table . trigger ( "stickyHeadersUpdate" ) , c . storage && ! d && c . storage ( this , c . css . resizableStorage , { } ) } } ) } } ( jQuery , window ) , function ( a ) { "use strict" ; var b = a . tablesorter || { } ;
// this widget saves the last sort only if the
// saveSort widget option is true AND the
// $.tablesorter.storage function is included
// **************************
b . addWidget ( { id : "saveSort" , priority : 20 , options : { saveSort : ! 0 } , init : function ( a , b , c , d ) {
// run widget format before all other widgets are applied to the table
b . format ( a , c , d , ! 0 ) } , format : function ( c , d , e , f ) { var g , h , i = d . $table , j = e . saveSort !== ! 1 , // make saveSort active/inactive; default to true
k = { sortList : d . sortList } ; d . debug && ( h = new Date ) , i . hasClass ( "hasSaveSort" ) ? j && c . hasInitialized && b . storage && ( b . storage ( c , "tablesorter-savesort" , k ) , d . debug && console . log ( "saveSort widget: Saving last sort: " + d . sortList + b . benchmark ( h ) ) ) : (
// set table sort on initial run of the widget
i . addClass ( "hasSaveSort" ) , k = "" , b . storage && ( g = b . storage ( c , "tablesorter-savesort" ) , k = g && g . hasOwnProperty ( "sortList" ) && a . isArray ( g . sortList ) ? g . sortList : "" , d . debug && console . log ( 'saveSort: Last sort loaded: "' + k + '"' + b . benchmark ( h ) ) , i . bind ( "saveSortReset" , function ( a ) { a . stopPropagation ( ) , b . storage ( c , "tablesorter-savesort" , "" ) } ) ) , f && k && k . length > 0 ? d . sortList = k : c . hasInitialized && k && k . length > 0 && b . sortOn ( d , k ) ) } , remove : function ( a , c ) { c . $table . removeClass ( "hasSaveSort" ) ,
// clear storage
b . storage && b . storage ( a , "tablesorter-savesort" , "" ) } } ) } ( jQuery ) , a . tablesorter } ) ;