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-05 02:15:37 +00:00
/*! tablesorter (FORK) - updated 11-04-2015 (v2.24.3)*/
2015-10-31 15:08:21 +00:00
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
2015-11-05 02:15:37 +00:00
! 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 ) { "use strict" ; var b = a . tablesorter = { version : "2.24.3" , parsers : [ ] , widgets : [ ] , defaults : {
2015-10-31 15:08:21 +00:00
// *** appearance
theme : "default" , // adds tablesorter-{theme} to the table for styling
widthFixed : ! 1 , // adds colgroup to fix widths of columns
showProcessing : ! 1 , // show an indeterminate timer icon in the header when the table is sorted or filtered.
headerTemplate : "{content}" , // header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> // class from cssIcon
onRenderTemplate : null , // function( index, template ){ return template; }, // template is a string
onRenderHeader : null , // function( index ){}, // nothing to return
// *** functionality
cancelSelection : ! 0 , // prevent text selection in the header
tabIndex : ! 0 , // add tabindex to header for keyboard accessibility
dateFormat : "mmddyyyy" , // other options: 'ddmmyyy' or 'yyyymmdd'
sortMultiSortKey : "shiftKey" , // key used to select additional columns
sortResetKey : "ctrlKey" , // key used to remove sorting on a column
usNumberFormat : ! 0 , // false for German '1.234.567,89' or French '1 234 567,89'
delayInit : ! 1 , // if false, the parsed table contents will not update until the first sort
serverSideSorting : ! 1 , // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
resort : ! 0 , // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
// *** sort options
headers : { } , // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
ignoreCase : ! 0 , // ignore case while sorting
sortForce : null , // column(s) first sorted; always applied
sortList : [ ] , // Initial sort order; applied initially; updated when manually sorted
sortAppend : null , // column(s) sorted last; always applied
sortStable : ! 1 , // when sorting two rows with exactly the same content, the original sort order is maintained
sortInitialOrder : "asc" , // sort direction on first click
sortLocaleCompare : ! 1 , // replace equivalent character (accented characters)
sortReset : ! 1 , // third click on the header will reset column to default - unsorted
sortRestart : ! 1 , // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
emptyTo : "bottom" , // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
stringTo : "max" , // sort strings in numerical column as max, min, top, bottom, zero
textExtraction : "basic" , // text extraction method/function - function( node, table, cellIndex ){}
textAttribute : "data-text" , // data-attribute that contains alternate cell text (used in default textExtraction function)
textSorter : null , // choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
numberSorter : null , // choose overall numeric sorter function( a, b, direction, maxColumnValue )
// *** widget options
widgets : [ ] , // method to add widgets, e.g. widgets: ['zebra']
widgetOptions : { zebra : [ "even" , "odd" ] } , initWidgets : ! 0 , // apply widgets on tablesorter initialization
widgetClass : "widget-{name}" , // table class name template to match to include a widget
// *** callbacks
initialized : null , // function( table ){},
// *** extra css class names
tableClass : "" , cssAsc : "" , cssDesc : "" , cssNone : "" , cssHeader : "" , cssHeaderRow : "" , cssProcessing : "" , // processing icon applied to header during sort/filter
cssChildRow : "tablesorter-childRow" , // class name indiciating that a row is to be attached to the its parent
cssInfoBlock : "tablesorter-infoOnly" , // don't sort tbody with this class name (only one class name allowed here!)
cssNoSort : "tablesorter-noSort" , // class name added to element inside header; clicking on it won't cause a sort
cssIgnoreRow : "tablesorter-ignoreRow" , // header row to ignore; cells within this row will not be added to c.$headers
cssIcon : "tablesorter-icon" , // if this class does not exist, the {icon} will not be added from the headerTemplate
cssIconNone : "" , // class name added to the icon when there is no column sort
cssIconAsc : "" , // class name added to the icon when the column has an ascending sort
cssIconDesc : "" , // class name added to the icon when the column has a descending sort
// *** events
pointerClick : "click" , pointerDown : "mousedown" , pointerUp : "mouseup" ,
// *** selectors
selectorHeaders : "> thead th, > thead td" , selectorSort : "th, td" , // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
selectorRemove : ".remove-me" ,
// *** advanced
debug : ! 1 ,
// *** Internal variables
headerList : [ ] , empties : { } , strings : { } , parsers : [ ] } ,
// internal css classes - these will ALWAYS be added to
// the table and MUST only contain one class name - fixes #381
css : { table : "tablesorter" , cssHasChild : "tablesorter-hasChildRow" , childRow : "tablesorter-childRow" , colgroup : "tablesorter-colgroup" , header : "tablesorter-header" , headerRow : "tablesorter-headerRow" , headerIn : "tablesorter-header-inner" , icon : "tablesorter-icon" , processing : "tablesorter-processing" , sortAsc : "tablesorter-headerAsc" , sortDesc : "tablesorter-headerDesc" , sortNone : "tablesorter-headerUnSorted" } ,
// labels applied to sortable headers for accessibility (aria) support
language : { sortAsc : "Ascending sort applied, " , sortDesc : "Descending sort applied, " , sortNone : "No sort applied, " , nextAsc : "activate to apply an ascending sort" , nextDesc : "activate to apply a descending sort" , nextNone : "activate to remove the sort" } , regex : { templateContent : /\{content\}/g , templateIcon : /\{icon\}/g , templateName : /\{name\}/i , spaces : /\s+/g , nonWord : /\W/g , formElements : /(input|select|button|textarea)/i ,
// *** sort functions ***
// regex used in natural sort
// chunk/tokenize numbers & letters
chunk : /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi ,
// replace chunks @ ends
chunks : /(^\\0|\\0$)/ , hex : /^0x[0-9a-f]+$/i ,
// *** formatFloat ***
comma : /,/g , digitNonUS : /[\s|\.]/g , digitNegativeTest : /^\s*\([.\d]+\)/ , digitNegativeReplace : /^\s*\(([.\d]+)\)/ ,
// *** isDigit ***
digitTest : /^[\-+(]?\d+[)]?$/ , digitReplace : /[,.'"\s]/g } ,
// digit sort text location; keeping max+/- for backwards compatibility
string : { max : 1 , min : - 1 , emptymin : 1 , emptymax : - 1 , zero : 0 , none : 0 , "null" : 0 , top : ! 0 , bottom : ! 1 } ,
// These methods can be applied on table.config instance
instanceMethods : { } , / *
▄ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄
▀ █ ▄ █ █ ▄ ▄ █ █ █ █ █ █ █ █ ▄ ▄ █ █
▀ █ ▄ █ █ ▀ ▀ █ █ █ █ █ █ █ █ ▀ ▀ ▀
█ █ █ █ █ ▀ █ █ █ █ █ █ █ █ ▀ █ █ █ █ ▀ █ █
* /
setup : function ( c , d ) {
// if no thead or tbody, or tablesorter is already present, quit
if ( ! c || ! c . tHead || 0 === c . tBodies . length || c . hasInitialized === ! 0 ) return void ( d . debug && ( c . hasInitialized ? console . warn ( "Stopping initialization. Tablesorter has already been initialized" ) : console . error ( "Stopping initialization! No table, thead or tbody" ) ) ) ; var e = "" , f = a ( c ) , g = a . metadata ;
// initialization flag
c . hasInitialized = ! 1 ,
// table is being processed flag
c . isProcessing = ! 0 ,
// make sure to store the config object
c . config = d ,
// save the settings where they read
a . data ( c , "tablesorter" , d ) , d . debug && ( console [ console . group ? "group" : "log" ] ( "Initializing tablesorter" ) , a . data ( c , "startoveralltimer" , new Date ) ) ,
// removing this in version 3 (only supports jQuery 1.7+)
d . supportsDataObject = function ( a ) { return a [ 0 ] = parseInt ( a [ 0 ] , 10 ) , a [ 0 ] > 1 || 1 === a [ 0 ] && parseInt ( a [ 1 ] , 10 ) >= 4 } ( a . fn . jquery . split ( "." ) ) ,
// ensure case insensitivity
d . emptyTo = d . emptyTo . toLowerCase ( ) , d . stringTo = d . stringTo . toLowerCase ( ) , d . last = { sortList : [ ] , clickedIndex : - 1 } ,
// add table theme class only if there isn't already one there
/tablesorter\-/ . test ( f . attr ( "class" ) ) || ( e = "" !== d . theme ? " tablesorter-" + d . theme : "" ) , d . table = c , d . $table = f . addClass ( b . css . table + " " + d . tableClass + e ) . attr ( "role" , "grid" ) , d . $headers = f . find ( d . selectorHeaders ) ,
// give the table a unique id, which will be used in namespace binding
d . namespace ? d . namespace = "." + d . namespace . replace ( b . regex . nonWord , "" ) : d . namespace = ".tablesorter" + Math . random ( ) . toString ( 16 ) . slice ( 2 ) , d . $table . children ( ) . children ( "tr" ) . attr ( "role" , "row" ) , d . $tbodies = f . children ( "tbody:not(." + d . cssInfoBlock + ")" ) . attr ( { "aria-live" : "polite" , "aria-relevant" : "all" } ) , d . $table . children ( "caption" ) . length && ( e = d . $table . children ( "caption" ) [ 0 ] , e . id || ( e . id = d . namespace . slice ( 1 ) + "caption" ) , d . $table . attr ( "aria-labelledby" , e . id ) ) , d . widgetInit = { } , // keep a list of initialized widgets
// change textExtraction via data-attribute
d . textExtraction = d . $table . attr ( "data-text-extraction" ) || d . textExtraction || "basic" ,
// build headers
b . buildHeaders ( d ) ,
// fixate columns if the users supplies the fixedWidth option
// do this after theme has been applied
b . fixColumnWidth ( c ) ,
// add widgets from class name
b . addWidgetFromClass ( c ) ,
// add widget options before parsing (e.g. grouping widget has parser settings)
b . applyWidgetOptions ( c ) ,
// try to auto detect column type, and store in tables config
b . setupParsers ( d ) ,
// start total row count at zero
d . totalRows = 0 ,
// build the cache for the tbody cells
// delayInit will delay building the cache until the user starts a sort
d . delayInit || b . buildCache ( d ) ,
// bind all header events and methods
b . bindEvents ( c , d . $headers , ! 0 ) , b . bindMethods ( d ) ,
// get sort list from jQuery data or metadata
// in jQuery < 1.4, an error occurs when calling $table.data()
d . supportsDataObject && "undefined" != typeof f . data ( ) . sortlist ? d . sortList = f . data ( ) . sortlist : g && f . metadata ( ) && f . metadata ( ) . sortlist && ( d . sortList = f . metadata ( ) . sortlist ) ,
// apply widget init code
b . applyWidget ( c , ! 0 ) ,
// if user has supplied a sort list to constructor
d . sortList . length > 0 ? b . sortOn ( d , d . sortList , { } , ! d . initWidgets ) : ( b . setHeadersCss ( d ) , d . initWidgets &&
// apply widget format
b . applyWidget ( c , ! 1 ) ) ,
// show processesing icon
d . showProcessing && f . unbind ( "sortBegin" + d . namespace + " sortEnd" + d . namespace ) . bind ( "sortBegin" + d . namespace + " sortEnd" + d . namespace , function ( a ) { clearTimeout ( d . processTimer ) , b . isProcessing ( c ) , "sortBegin" === a . type && ( d . processTimer = setTimeout ( function ( ) { b . isProcessing ( c , ! 0 ) } , 500 ) ) } ) ,
// initialized
c . hasInitialized = ! 0 , c . isProcessing = ! 1 , d . debug && ( console . log ( "Overall initialization time: " + b . benchmark ( a . data ( c , "startoveralltimer" ) ) ) , d . debug && console . groupEnd && console . groupEnd ( ) ) , f . trigger ( "tablesorter-initialized" , c ) , "function" == typeof d . initialized && d . initialized ( c ) } , bindMethods : function ( c ) { var d = c . $table , e = c . namespace , f = "sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave " . split ( " " ) . join ( e + " " ) ;
// apply easy methods that trigger bound events
d . unbind ( f . replace ( b . regex . spaces , " " ) ) . bind ( "sortReset" + e , function ( a , c ) { a . stopPropagation ( ) ,
// using this.config to ensure functions are getting a non-cached version of the config
b . sortReset ( this . config , c ) } ) . bind ( "updateAll" + e , function ( a , c , d ) { a . stopPropagation ( ) , b . updateAll ( this . config , c , d ) } ) . bind ( "update" + e + " updateRows" + e , function ( a , c , d ) { a . stopPropagation ( ) , b . update ( this . config , c , d ) } ) . bind ( "updateHeaders" + e , function ( a , c ) { a . stopPropagation ( ) , b . updateHeaders ( this . config , c ) } ) . bind ( "updateCell" + e , function ( a , c , d , e ) { a . stopPropagation ( ) , b . updateCell ( this . config , c , d , e ) } ) . bind ( "addRows" + e , function ( a , c , d , e ) { a . stopPropagation ( ) , b . addRows ( this . config , c , d , e ) } ) . bind ( "updateComplete" + e , function ( ) { this . isUpdating = ! 1 } ) . bind ( "sorton" + e , function ( a , c , d , e ) { a . stopPropagation ( ) , b . sortOn ( this . config , c , d , e ) } ) . bind ( "appendCache" + e , function ( c , d , e ) { c . stopPropagation ( ) , b . appendCache ( this . config , e ) , a . isFunction ( d ) && d ( this ) } ) . bind ( "updateCache" + e , function ( a , c , d ) { a . stopPropagation ( ) , b . updateCache ( this . config , c , d ) } ) . bind ( "applyWidgetId" + e , function ( a , c ) { a . stopPropagation ( ) , b . getWidgetById ( c ) . format ( this , this . config , this . config . widgetOptions ) } ) . bind ( "applyWidgets" + e , function ( a , c ) { a . stopPropagation ( ) ,
// apply widgets
b . applyWidget ( this , c ) } ) . bind ( "refreshWidgets" + e , function ( a , c , d ) { a . stopPropagation ( ) , b . refreshWidgets ( this , c , d ) } ) . bind ( "destroy" + e , function ( a , c , d ) { a . stopPropagation ( ) , b . destroy ( this , c , d ) } ) . bind ( "resetToLoadState" + e , function ( d ) { d . stopPropagation ( ) ,
// remove all widgets
b . removeWidget ( this , ! 0 , ! 1 ) , c = a . extend ( ! 0 , b . defaults , c . originalSettings ) , this . hasInitialized = ! 1 , b . setup ( this , c ) } ) } , bindEvents : function ( c , d , e ) { c = a ( c ) [ 0 ] ; var f , g = c . config , h = g . namespace , i = null ; e !== ! 0 && ( d . addClass ( h . slice ( 1 ) + "_extra_headers" ) , f = a . fn . closest ? d . closest ( "table" ) [ 0 ] : d . parents ( "table" ) [ 0 ] , f && "TABLE" === f . nodeName && f !== c && a ( f ) . addClass ( h . slice ( 1 ) + "_extra_table" ) ) , f = ( g . pointerDown + " " + g . pointerUp + " " + g . pointerClick + " sort keyup " ) . replace ( b . regex . spaces , " " ) . split ( " " ) . join ( h + " " ) , d . find ( g . selectorSort ) . add ( d . filter ( g . selectorSort ) ) . unbind ( f ) . bind ( f , function ( c , e ) { var f , h , j , k = a ( c . target ) , l = " " + c . type + " " ; if ( ! ( 1 !== ( c . which || c . button ) && ! l . match ( " " + g . pointerClick + " | sort | keyup " ) || " keyup " === l && 13 !== c . which || l . match ( " " + g . pointerClick + " " ) && "undefined" != typeof c . which || l . match ( " " + g . pointerUp + " " ) && i !== c . target && e !== ! 0 ) ) { if ( l . match ( " " + g . pointerDown + " " ) ) return i = c . target , j = k . jquery . split ( "." ) , void ( "1" === j [ 0 ] && j [ 1 ] < 4 && c . preventDefault ( ) ) ; if ( i = null , b . regex . formElements . test ( c . target . nodeName ) || k . hasClass ( g . cssNoSort ) || k . parents ( "." + g . cssNoSort ) . length > 0 || k . parents ( "button" ) . length > 0 ) return ! g . cancelSelection ; g . delayInit && b . isEmptyObject ( g . cache ) && b . buildCache ( g ) , f = a . fn . closest ? a ( this ) . closest ( "th, td" ) : /TH|TD/ . test ( this . nodeName ) ? a ( this ) : a ( this ) . parents ( "th, td" ) , j = d . index ( f ) , g . last . clickedIndex = 0 > j ? f . attr ( "data-column" ) : j , h = g . $headers [ g . last . clickedIndex ] , h && ! h . sortDisabled && b . initSort ( g , h , c ) } } ) , g . cancelSelection && d . attr ( "unselectable" , "on" ) . bind ( "selectstart" , ! 1 ) . css ( { "user-select" : "none" , MozUserSelect : "none" } ) } , buildHeaders : function ( c ) { var d , e , f , g ; for ( c . headerList = [ ] , c . headerContent = [ ] , c . sortVars = [ ] , c . debug && ( f = new Date ) ,
// children tr in tfoot - see issue #196 & #547
c . columns = b . computeColumnIndex ( c . $table . children ( "thead, tfoot" ) . children ( "tr" ) ) , e = c . cssIcon ? '<i class="' + ( c . cssIcon === b . css . icon ? b . css . icon : c . cssIcon + " " + b . css . icon ) + '"></i>' : "" , c . $headers = a ( a . map ( c . $table . find ( c . selectorHeaders ) , function ( d , f ) { var g , h , i , j , k , l = a ( d ) ; if ( ! l . parent ( ) . hasClass ( c . cssIgnoreRow ) ) return g = b . getColumnData ( c . table , c . headers , f , ! 0 ) , c . headerContent [ f ] = l . html ( ) , "" === c . headerTemplate || l . find ( "." + b . css . headerIn ) . length || ( j = c . headerTemplate . replace ( b . regex . templateContent , l . html ( ) ) . replace ( b . regex . templateIcon , l . find ( "." + b . css . icon ) . length ? "" : e ) , c . onRenderTemplate && ( h = c . onRenderTemplate . apply ( l , [ f , j ] ) , h && "string" == typeof h && ( j = h ) ) , l . html ( '<div class="' + b . css . headerIn + '">' + j + "</div>" ) ) , c . onRenderHeader && c . onRenderHeader . apply ( l , [ f , c , c . $table ] ) , i = parseInt ( l . attr ( "data-column" ) , 10 ) , d . column = i , k = b . getData ( l , g , "sortInitialOrder" ) || c . sortInitialOrder , c . sortVars [ i ] = { count : - 1 , order : b . formatSortingOrder ( k ) ? [ 1 , 0 , 2 ] : [ 0 , 1 , 2 ] , lockedOrder : ! 1 } , k = b . getData ( l , g , "lockedOrder" ) || ! 1 , "undefined" != typeof k && k !== ! 1 && ( c . sortVars [ i ] . lockedOrder = ! 0 , c . sortVars [ i ] . order = b . formatSortingOrder ( k ) ? [ 1 , 1 , 1 ] : [ 0 , 0 , 0 ] ) , c . headerList [ f ] = d , l . addClass ( b . css . header + " " + c . cssHeader ) . parent ( ) . addClass ( b . css . headerRow + " " + c . cssHeaderRow ) . attr ( "role" , "row" ) , c . tabIndex && l . attr ( "tabindex" , 0 ) , d } ) ) , c . $headerIndexed = [ ] , g = 0 ; g < c . columns ; g ++ )
// colspan in header making a column undefined
b . isEmptyObject ( c . sortVars [ g ] ) && ( c . sortVars [ g ] = { } ) , d = c . $headers . filter ( '[data-column="' + g + '"]' ) , c . $headerIndexed [ g ] = d . length ? d . not ( ".sorter-false" ) . length ? d . not ( ".sorter-false" ) . filter ( ":last" ) : d . filter ( ":last" ) : a ( ) ; c . $table . find ( c . selectorHeaders ) . attr ( { scope : "col" , role : "columnheader" } ) ,
// enable/disable sorting
b . updateHeader ( c ) , c . debug && ( console . log ( "Built headers:" + b . benchmark ( f ) ) , console . log ( c . $headers ) ) } ,
// Use it to add a set of methods to table.config which will be available for all tables.
// This should be done before table initialization
addInstanceMethods : function ( c ) { a . extend ( b . instanceMethods , c ) } , / *
█ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ ▄ ▄ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ █ █ █ █ █
█ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █ ▀ █ ▄ █ █ ▄ ▄ █ █ ▄ ▄ █ █ ▀ █ ▄
█ █ ▀ ▀ ▀ █ █ ▀ ▀ █ █ █ █ ▀ █ █ ▀ █ ▄ █ █ ▀ ▀ █ █ ▀ █ █ ▀ █ ▄
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀
* /
setupParsers : function ( a , c ) { var d , e , f , g , h , i , j , k , l , m , n , o , p , q , r = a . table , s = 0 , t = { } ; if (
// update table bodies in case we start with an empty table
a . $tbodies = a . $table . children ( "tbody:not(." + a . cssInfoBlock + ")" ) , p = "undefined" == typeof c ? a . $tbodies : c , q = p . length , 0 === q ) return a . debug ? console . warn ( "Warning: *Empty table!* Not building a parser cache" ) : "" ; for ( a . debug && ( o = new Date , console [ console . group ? "group" : "log" ] ( "Detecting parsers for each column" ) ) , e = { extractors : [ ] , parsers : [ ] } ; q > s ; ) { if ( d = p [ s ] . rows , d . length ) for ( h = 0 , g = a . columns , i = 0 ; g > i ; i ++ ) j = a . $headerIndexed [ h ] , j && j . length && ( k = b . getColumnData ( r , a . headers , h ) , n = b . getParserById ( b . getData ( j , k , "extractor" ) ) , m = b . getParserById ( b . getData ( j , k , "sorter" ) ) , l = "false" === b . getData ( j , k , "parser" ) , a . empties [ h ] = ( b . getData ( j , k , "empty" ) || a . emptyTo || ( a . emptyToBottom ? "bottom" : "top" ) ) . toLowerCase ( ) , a . strings [ h ] = ( b . getData ( j , k , "string" ) || a . stringTo || "max" ) . toLowerCase ( ) , l && ( m = b . getParserById ( "no-parser" ) ) , n || ( n = ! 1 ) , m || ( m = b . detectParserForColumn ( a , d , - 1 , h ) ) , a . debug && ( t [ "(" + h + ") " + j . text ( ) ] = { parser : m . id , extractor : n ? n . id : "none" , string : a . strings [ h ] , empty : a . empties [ h ] } ) , e . parsers [ h ] = m , e . extractors [ h ] = n , f = j [ 0 ] . colSpan - 1 , f > 0 && ( h += f , g += f ) ) , h ++ ; s += e . parsers . length ? q : 1 } a . debug && ( b . isEmptyObject ( t ) ? console . warn ( " No parsers detected!" ) : console [ console . table ? "table" : "log" ] ( t ) , console . log ( "Completed detecting parsers" + b . benchmark ( o ) ) , console . groupEnd && console . groupEnd ( ) ) , a . parsers = e . parsers , a . extractors = e . extractors } , addParser : function ( a ) { var c , d = b . parsers . length , e = ! 0 ; for ( c = 0 ; d > c ; c ++ ) b . parsers [ c ] . id . toLowerCase ( ) === a . id . toLowerCase ( ) && ( e = ! 1 ) ; e && b . parsers . push ( a ) } , getParserById : function ( a ) { /*jshint eqeqeq:false */
if ( "false" == a ) return ! 1 ; var c , d = b . parsers . length ; for ( c = 0 ; d > c ; c ++ ) if ( b . parsers [ c ] . id . toLowerCase ( ) === a . toString ( ) . toLowerCase ( ) ) return b . parsers [ c ] ; return ! 1 } , detectParserForColumn : function ( c , d , e , f ) { for ( var g , h , i = b . parsers . length , j = ! 1 , k = "" , l = ! 0 ; "" === k && l ; ) e ++ , d [ e ] ? ( j = d [ e ] . cells [ f ] , k = b . getElementText ( c , j , f ) , h = a ( j ) , c . debug && console . log ( "Checking if value was empty on row " + e + ", column: " + f + ': "' + k + '"' ) ) : l = ! 1 ; for ( ; -- i >= 0 ; )
// ignore the default text parser because it will always be true
if ( g = b . parsers [ i ] , g && "text" !== g . id && g . is && g . is ( k , c . table , j , h ) ) return g ;
// nothing found, return the generic parser (text)
return b . getParserById ( "text" ) } , getElementText : function ( c , d , e ) { if ( ! d ) return "" ; var f , g = c . textExtraction || "" ,
// node could be a jquery object
// http://jsperf.com/jquery-vs-instanceof-jquery/2
h = d . jquery ? d : a ( d ) ;
// check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
// http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
return "string" == typeof g ? "basic" === g && "undefined" != typeof ( f = h . attr ( c . textAttribute ) ) ? a . trim ( f ) : a . trim ( d . textContent || h . text ( ) ) : "function" == typeof g ? a . trim ( g ( h [ 0 ] , c . table , e ) ) : "function" == typeof ( f = b . getColumnData ( c . table , g , e ) ) ? a . trim ( f ( h [ 0 ] , c . table , e ) ) : a . trim ( h [ 0 ] . textContent || h . text ( ) ) } ,
// centralized function to extract/parse cell contents
getParsedText : function ( a , c , d , e ) { "undefined" == typeof e && ( e = b . getElementText ( a , c , d ) ) ;
// if no parser, make sure to return the txt
var f = "" + e , g = a . parsers [ d ] , h = a . extractors [ d ] ;
// do extract before parsing, if there is one
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
// make sure txt is a string (extractor may have converted it)
return g && ( h && "function" == typeof h . format && ( e = h . format ( e , a . table , c , d ) ) , f = "no-parser" === g . id ? "" : g . format ( "" + e , a . table , c , d ) , a . ignoreCase && "string" == typeof f && ( f = f . toLowerCase ( ) ) ) , f } , / *
▄ █ █ █ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ █ █ █ █ █
█ █ ▀ ▀ █ █ ▄ ▄ █ █ █ █ ▀ ▀ █ █ ▄ ▄ █ █ █ █ ▄ ▄
█ █ ▄ ▄ █ █ ▀ ▀ █ █ █ █ ▄ ▄ █ █ ▀ ▀ █ █ █ █ ▀ ▀
▀ █ █ █ █ ▀ █ █ █ █ ▀ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █
* /
buildCache : function ( c , d , e ) { var f , g , h , i , j , k , l , m , n , o , p , q , r , s , t , u , v , w , x , y , z = c . table , A = c . parsers ;
// if no parsers found, return - it's an empty table.
if (
// update tbody variable
c . $tbodies = c . $table . children ( "tbody:not(." + c . cssInfoBlock + ")" ) , l = "undefined" == typeof e ? c . $tbodies : e , c . cache = { } , c . totalRows = 0 , ! A ) return c . debug ? console . warn ( "Warning: *Empty table!* Not building a cache" ) : "" ; for ( c . debug && ( q = new Date ) ,
// processing icon
c . showProcessing && b . isProcessing ( z , ! 0 ) , k = 0 ; k < l . length ; k ++ ) { for ( u = [ ] , f = c . cache [ k ] = { normalized : [ ] } , r = l [ k ] && l [ k ] . rows . length || 0 , i = 0 ; r > i ; ++ i )
// if this is a child row, add it to the last row's children and continue to the next row
// ignore child row class, if it is the first row
if ( s = {
// order: original row order #
// $row : jQuery Object[]
child : [ ] , // child row text (filter widget)
raw : [ ] } , m = a ( l [ k ] . rows [ i ] ) , n = [ ] , m . hasClass ( c . cssChildRow ) && 0 !== i ) for ( y = f . normalized . length - 1 , t = f . normalized [ y ] [ c . columns ] , t . $row = t . $row . add ( m ) , m . prev ( ) . hasClass ( c . cssChildRow ) || m . prev ( ) . addClass ( b . css . cssHasChild ) , o = m . children ( "th, td" ) , y = t . child . length , t . child [ y ] = [ ] , w = 0 , x = c . columns , j = 0 ; x > j ; j ++ ) p = o [ j ] , p && ( t . child [ y ] [ j ] = b . getParsedText ( c , p , j ) , v = o [ j ] . colSpan - 1 , v > 0 && ( w += v , x += v ) ) , w ++ ; else { for ( s . $row = m , s . order = i , w = 0 , x = c . columns , j = 0 ; x > j ; ++ j ) p = m [ 0 ] . cells [ j ] , "undefined" == typeof A [ w ] ? c . debug && console . warn ( "No parser found for column " + j + "; cell:" , p , "does it have a header?" ) : p && ( g = b . getElementText ( c , p , w ) , s . raw [ w ] = g , h = b . getParsedText ( c , p , w , g ) , n [ w ] = h , "numeric" === ( A [ w ] . type || "" ) . toLowerCase ( ) && ( u [ w ] = Math . max ( Math . abs ( h ) || 0 , u [ w ] || 0 ) ) , v = p . colSpan - 1 , v > 0 && ( w += v , x += v ) ) , w ++ ;
// ensure rowData is always in the same location (after the last column)
n [ c . columns ] = s , f . normalized . push ( n ) } f . colMax = u ,
// total up rows, not including child rows
c . totalRows += f . normalized . length } c . showProcessing && b . isProcessing ( z ) , c . debug && console . log ( "Building cache for " + r + " rows" + b . benchmark ( q ) ) , a . isFunction ( d ) && d ( z ) } , getColumnText : function ( c , d , e , f ) { c = a ( c ) [ 0 ] ; var g , h , i , j , k , l , m , n , o , p , q = "function" == typeof e , r = "all" === d , s = { raw : [ ] , parsed : [ ] , $cell : [ ] } , t = c . config ; if ( ! b . isEmptyObject ( t ) ) { for ( k = t . $tbodies . length , g = 0 ; k > g ; g ++ ) for ( i = t . cache [ g ] . normalized , l = i . length , h = 0 ; l > h ; h ++ ) j = i [ h ] , ( ! f || j [ t . columns ] . $row . is ( f ) ) && ( p = ! 0 , n = r ? j . slice ( 0 , t . columns ) : j [ d ] , j = j [ t . columns ] , m = r ? j . raw : j . raw [ d ] , o = r ? j . $row . children ( ) : j . $row . children ( ) . eq ( d ) , q && ( p = e ( { tbodyIndex : g , rowIndex : h , parsed : n , raw : m , $row : j . $row , $cell : o } ) ) , p !== ! 1 && ( s . parsed . push ( n ) , s . raw . push ( m ) , s . $cell . push ( o ) ) ) ;
// return everything
return s } t . debug && console . warn ( "No cache found - aborting getColumnText function!" ) } , / *
█ █ █ █ █ █ █ █ █ ▄ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ ▄ ▄ █ █ █ █ █ █ █ █ ▄ ▄ █ █ █ █ █ █ ▄ ▄
█ █ █ █ █ █ ▀ ▀ ▀ █ █ █ █ █ █ ▀ ▀ █ █ █ █ █ █ ▀ ▀
▀ █ █ █ █ ▀ █ █ █ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █
* /
setHeadersCss : function ( c ) { var d , e , f , g , h , i , j , k , l = c . sortList , m = l . length , n = b . css . sortNone + " " + c . cssNone , o = [ b . css . sortAsc + " " + c . cssAsc , b . css . sortDesc + " " + c . cssDesc ] , p = [ c . cssIconAsc , c . cssIconDesc , c . cssIconNone ] , q = [ "ascending" , "descending" ] ,
// find the footer
r = c . $table . find ( "tfoot tr" ) . children ( ) . add ( a ( c . namespace + "_extra_headers" ) ) . removeClass ( o . join ( " " ) ) ; for (
// remove all header information
c . $headers . removeClass ( o . join ( " " ) ) . addClass ( n ) . attr ( "aria-sort" , "none" ) . find ( "." + b . css . icon ) . removeClass ( p . join ( " " ) ) . addClass ( p [ 2 ] ) , f = 0 ; m > f ; f ++ )
// direction = 2 means reset!
2015-11-05 02:15:37 +00:00
if ( 2 !== l [ f ] [ 1 ] && ( d = c . $headers . filter ( function ( a ) { for (
2015-10-31 15:08:21 +00:00
// only include headers that are in the sortList (this includes colspans)
2015-11-05 02:15:37 +00:00
var d = ! 0 , e = c . $headers . eq ( a ) , f = parseInt ( e . attr ( "data-column" ) , 10 ) , g = f + c . $headers [ a ] . colSpan ; g > f ; f ++ ) d = d ? b . isValueInArray ( f , c . sortList ) > - 1 : ! 1 ; return d } ) , d = d . not ( ".sorter-false" ) . filter ( '[data-column="' + l [ f ] [ 0 ] + '"]' + ( 1 === m ? ":last" : "" ) ) , d . length ) ) { for ( g = 0 ; g < d . length ; g ++ ) d [ g ] . sortDisabled || d . eq ( g ) . removeClass ( n ) . addClass ( o [ l [ f ] [ 1 ] ] ) . attr ( "aria-sort" , q [ l [ f ] [ 1 ] ] ) . find ( "." + b . css . icon ) . removeClass ( p [ 2 ] ) . addClass ( p [ l [ f ] [ 1 ] ] ) ;
2015-10-31 15:08:21 +00:00
// add sorted class to footer & extra headers, if they exist
r . length && r . filter ( '[data-column="' + l [ f ] [ 0 ] + '"]' ) . removeClass ( n ) . addClass ( o [ l [ f ] [ 1 ] ] ) } for ( m = c . $headers . length , r = c . $headers . not ( ".sorter-false" ) , f = 0 ; m > f ; f ++ ) h = r . eq ( f ) , h . length && ( e = r [ f ] , g = parseInt ( h . attr ( "data-column" ) , 10 ) , i = c . sortVars [ g ] . order [ ( c . sortVars [ g ] . count + 1 ) % ( c . sortReset ? 3 : 2 ) ] , k = h . hasClass ( b . css . sortAsc ) ? "sortAsc" : h . hasClass ( b . css . sortDesc ) ? "sortDesc" : "sortNone" , j = a . trim ( h . text ( ) ) + ": " + b . language [ k ] + b . language [ 0 === i ? "nextAsc" : 1 === i ? "nextDesc" : "nextNone" ] , h . attr ( "aria-label" , j ) ) } , updateHeader : function ( a ) { var c , d , e , f , g = a . table , h = a . $headers . length ; for ( c = 0 ; h > c ; c ++ ) e = a . $headers . eq ( c ) , f = b . getColumnData ( g , a . headers , c , ! 0 ) , d = "false" === b . getData ( e , f , "sorter" ) || "false" === b . getData ( e , f , "parser" ) , e [ 0 ] . sortDisabled = d , e [ d ? "addClass" : "removeClass" ] ( "sorter-false" ) . attr ( "aria-disabled" , "" + d ) , a . tabIndex && ( d ? e . removeAttr ( "tabindex" ) : e . attr ( "tabindex" , "0" ) ) , g . id && ( d ? e . removeAttr ( "aria-controls" ) : e . attr ( "aria-controls" , g . id ) ) } , updateHeaderSortCount : function ( b , c ) { var d , e , f , g , h , i , j , k , l = c || b . sortList , m = l . length ; for ( b . sortList = [ ] , g = 0 ; m > g ; g ++ )
// prevents error if sorton array is wrong
if ( j = l [ g ] , d = parseInt ( j [ 0 ] , 10 ) , d < b . columns ) {
// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
switch ( k = b . sortVars [ d ] . order , e = ( "" + j [ 1 ] ) . match ( /^(1|d|s|o|n)/ ) , e = e ? e [ 0 ] : "" ) { case "1" : case "d" : // descending
e = 1 ; break ; case "s" : // same direction (as primary column)
// if primary sort is set to 's', make it ascending
e = h || 0 ; break ; case "o" : i = k [ ( h || 0 ) % ( b . sortReset ? 3 : 2 ) ] ,
// opposite of primary column; but resets if primary resets
e = 0 === i ? 1 : 1 === i ? 0 : 2 ; break ; case "n" : e = k [ ++ b . sortVars [ d ] . count % ( b . sortReset ? 3 : 2 ) ] ; break ; default : // ascending
e = 0 } h = 0 === g ? e : h , f = [ d , parseInt ( e , 10 ) || 0 ] , b . sortList . push ( f ) , e = a . inArray ( f [ 1 ] , k ) , // fixes issue #167
b . sortVars [ d ] . count = e >= 0 ? e : f [ 1 ] % ( b . sortReset ? 3 : 2 ) } } , updateAll : function ( a , c , d ) { var e = a . table ; e . isUpdating = ! 0 , b . refreshWidgets ( e , ! 0 , ! 0 ) , b . buildHeaders ( a ) , b . bindEvents ( e , a . $headers , ! 0 ) , b . bindMethods ( a ) , b . commonUpdate ( a , c , d ) } , update : function ( a , c , d ) { var e = a . table ; e . isUpdating = ! 0 ,
// update sorting (if enabled/disabled)
b . updateHeader ( a ) , b . commonUpdate ( a , c , d ) } ,
// simple header update - see #989
updateHeaders : function ( a , c ) { a . table . isUpdating = ! 0 , b . buildHeaders ( a ) , b . bindEvents ( a . table , a . $headers , ! 0 ) , b . resortComplete ( a , c ) } , updateCell : function ( c , d , e , f ) { c . table . isUpdating = ! 0 , c . $table . find ( c . selectorRemove ) . remove ( ) ;
// get position from the dom
var g , h , i , j , k , l , m = c . $tbodies , n = a ( d ) ,
// update cache - format: function( s, table, cell, cellIndex )
// no closest in jQuery v1.2.6
o = m . index ( a . fn . closest ? n . closest ( "tbody" ) : n . parents ( "tbody" ) . filter ( ":first" ) ) , p = c . cache [ o ] , q = a . fn . closest ? n . closest ( "tr" ) : n . parents ( "tr" ) . filter ( ":first" ) ; // in case cell is a jQuery object
// tbody may not exist if update is initialized while tbody is removed for processing
if ( d = n [ 0 ] , m . length && o >= 0 ) { if ( i = m . eq ( o ) . find ( "tr" ) . index ( q ) , k = p . normalized [ i ] , l = q [ 0 ] . cells . length , l !== c . columns ) for ( j = 0 , g = ! 1 , h = 0 ; l > h ; h ++ ) g || q [ 0 ] . cells [ h ] === d ? g = ! 0 : j += q [ 0 ] . cells [ h ] . colSpan ; else j = n . index ( ) ; g = b . getElementText ( c , d , j ) , // raw
k [ c . columns ] . raw [ j ] = g , g = b . getParsedText ( c , d , j , g ) , k [ j ] = g , // parsed
k [ c . columns ] . $row = q , "numeric" === ( c . parsers [ j ] . type || "" ) . toLowerCase ( ) && (
// update column max value (ignore sign)
p . colMax [ j ] = Math . max ( Math . abs ( g ) || 0 , p . colMax [ j ] || 0 ) ) , g = "undefined" !== e ? e : c . resort , g !== ! 1 ?
// widgets will be reapplied
b . checkResort ( c , g , f ) :
// don't reapply widgets is resort is false, just in case it causes
// problems with element focus
b . resortComplete ( c , f ) } } , addRows : function ( c , d , e , f ) { var g , h , i , j , k , l , m , n , o , p , q , r ,
// allow passing a row string if only one non-info tbody exists in the table
s = "string" == typeof d && 1 === c . $tbodies . length && /<tr/ . test ( d || "" ) , t = c . table ; if ( s ) d = a ( d ) , c . $tbodies . append ( d ) ; else if ( ! ( d && d instanceof jQuery && ( a . fn . closest ? d . closest ( "table" ) [ 0 ] : d . parents ( "table" ) [ 0 ] ) === c . table ) ) return c . debug && console . error ( "addRows method requires (1) a jQuery selector reference to rows that have already been added to the table, or (2) row HTML string to be added to a table with only one tbody" ) , ! 1 ; if ( t . isUpdating = ! 0 , b . isEmptyObject ( c . cache ) )
// empty table, do an update instead - fixes #450
b . updateHeader ( c ) , b . commonUpdate ( c , e , f ) ; else {
// add each row
for ( k = d . filter ( "tr" ) . attr ( "role" , "row" ) . length , i = c . $tbodies . index ( d . parents ( "tbody" ) . filter ( ":first" ) ) , c . parsers && c . parsers . length || b . setupParsers ( c ) , j = 0 ; k > j ; j ++ ) {
// add each cell
for ( n = 0 , m = d [ j ] . cells . length , p = [ ] , o = { child : [ ] , raw : [ ] , $row : d . eq ( j ) , order : c . cache [ i ] . normalized . length } , l = 0 ; m > l ; l ++ ) q = d [ j ] . cells [ l ] , g = b . getElementText ( c , q , n ) , o . raw [ n ] = g , h = b . getParsedText ( c , q , n , g ) , p [ n ] = h , "numeric" === ( c . parsers [ n ] . type || "" ) . toLowerCase ( ) && ( c . cache [ i ] . colMax [ n ] = Math . max ( Math . abs ( h ) || 0 , c . cache [ i ] . colMax [ n ] || 0 ) ) , r = q . colSpan - 1 , r > 0 && ( n += r ) , n ++ ;
// add the row data to the end
p [ c . columns ] = o ,
// update cache
c . cache [ i ] . normalized . push ( p ) }
// resort using current settings
b . checkResort ( c , e , f ) } } , updateCache : function ( a , c , d ) {
// rebuild parsers
a . parsers && a . parsers . length || b . setupParsers ( a , d ) ,
// rebuild the cache map
b . buildCache ( a , c , d ) } ,
// init flag (true) used by pager plugin to prevent widget application
// renamed from appendToTable
appendCache : function ( a , c ) { var d , e , f , g , h , i , j , k = a . table , l = a . widgetOptions , m = a . $tbodies , n = [ ] , o = a . cache ;
// empty table - fixes #206/#346
if ( b . isEmptyObject ( o ) )
// run pager appender in case the table was just emptied
return a . appender ? a . appender ( k , n ) : k . isUpdating ? a . $table . trigger ( "updateComplete" , k ) : "" ; for ( a . debug && ( j = new Date ) , i = 0 ; i < m . length ; i ++ ) if ( f = m . eq ( i ) , f . length ) { for ( g = b . processTbody ( k , f , ! 0 ) , d = o [ i ] . normalized , e = d . length , h = 0 ; e > h ; h ++ ) n . push ( d [ h ] [ a . columns ] . $row ) ,
// removeRows used by the pager plugin; don't render if using ajax - fixes #411
a . appender && ( ! a . pager || a . pager . removeRows && l . pager _removeRows || a . pager . ajax ) || g . append ( d [ h ] [ a . columns ] . $row ) ;
// restore tbody
b . processTbody ( k , g , ! 1 ) } a . appender && a . appender ( k , n ) , a . debug && console . log ( "Rebuilt table" + b . benchmark ( j ) ) ,
// apply table widgets; but not before ajax completes
c || a . appender || b . applyWidget ( k ) , k . isUpdating && a . $table . trigger ( "updateComplete" , k ) } , commonUpdate : function ( a , c , d ) {
// remove rows/elements before update
a . $table . find ( a . selectorRemove ) . remove ( ) ,
// rebuild parsers
b . setupParsers ( a ) ,
// rebuild the cache map
b . buildCache ( a ) , b . checkResort ( a , c , d ) } , / *
▄ █ █ █ █ █ ▄ █ █ █ █ ▄ █ █ █ █ █ ▄ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄
▀ █ ▄ █ █ █ █ █ █ ▄ ▄ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ ▄
▀ █ ▄ █ █ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █ ▀ █ █
█ █ █ █ █ ▀ ▀ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █ ▀ █ █ █ █ ▀
* /
initSort : function ( c , d , e ) { if ( c . table . isUpdating )
// let any updates complete before initializing a sort
return setTimeout ( function ( ) { b . initSort ( c , d , e ) } , 50 ) ; var f , g , h , i , j , k , l , m = ! e [ c . sortMultiSortKey ] , n = c . table , o = c . $headers . length ,
// get current column index
p = parseInt ( a ( d ) . attr ( "data-column" ) , 10 ) , q = c . sortVars [ p ] . order ;
// reset all sorts on non-current column - issue #30
if (
// Only call sortStart if sorting is enabled
c . $table . trigger ( "sortStart" , n ) ,
// get current column sort order
2015-11-05 02:15:37 +00:00
c . sortVars [ p ] . count = e [ c . sortResetKey ] ? 2 : ( c . sortVars [ p ] . count + 1 ) % ( c . sortReset ? 3 : 2 ) , c . sortRestart ) for ( k = d , h = 0 ; o > h ; h ++ ) l = c . $headers . eq ( h ) , l [ 0 ] !== k && ( m || l . hasClass ( b . css . sortNone ) ) && ( c . sortVars [ l . attr ( "data-column" ) ] . count = - 1 ) ;
2015-10-31 15:08:21 +00:00
// user only wants to sort on one column
if ( m ) { if (
// flush the sort list
c . sortList = [ ] , c . last . sortList = [ ] , null !== c . sortForce ) for ( f = c . sortForce , g = 0 ; g < f . length ; g ++ ) f [ g ] [ 0 ] !== p && c . sortList . push ( f [ g ] ) ; if ( i = q [ c . sortVars [ p ] . count ] , 2 > i && ( c . sortList . push ( [ p , i ] ) , d . colSpan > 1 ) ) for ( g = 1 ; g < d . colSpan ; g ++ ) c . sortList . push ( [ p + g , i ] ) ,
// update count on columns in colSpan
c . sortVars [ p + g ] . count = a . inArray ( i , q ) } else
// the user has clicked on an already sorted column
if (
// get rid of the sortAppend before adding more - fixes issue #115 & #523
c . sortList = a . extend ( [ ] , c . last . sortList ) , b . isValueInArray ( p , c . sortList ) >= 0 )
// reverse the sorting direction
for ( g = 0 ; g < c . sortList . length ; g ++ ) k = c . sortList [ g ] , k [ 0 ] === p && ( k [ 1 ] = q [ c . sortVars [ p ] . count ] , 2 === k [ 1 ] && ( c . sortList . splice ( g , 1 ) , c . sortVars [ p ] . count = - 1 ) ) ; else if ( i = q [ c . sortVars [ p ] . count ] , 2 > i && ( c . sortList . push ( [ p , i ] ) , d . colSpan > 1 ) ) for ( g = 1 ; g < d . colSpan ; g ++ ) c . sortList . push ( [ p + g , i ] ) ,
// update count on columns in colSpan
c . sortVars [ p + g ] . count = a . inArray ( i , q ) ; if (
// save sort before applying sortAppend
c . last . sortList = a . extend ( [ ] , c . sortList ) , c . sortList . length && c . sortAppend && ( f = a . isArray ( c . sortAppend ) ? c . sortAppend : c . sortAppend [ c . sortList [ 0 ] [ 0 ] ] , ! b . isEmptyObject ( f ) ) ) for ( g = 0 ; g < f . length ; g ++ ) if ( f [ g ] [ 0 ] !== p && b . isValueInArray ( f [ g ] [ 0 ] , c . sortList ) < 0 ) { if ( i = f [ g ] [ 1 ] , j = ( "" + i ) . match ( /^(a|d|s|o|n)/ ) ) switch ( k = c . sortList [ 0 ] [ 1 ] , j [ 0 ] ) { case "d" : i = 1 ; break ; case "s" : i = k ; break ; case "o" : i = 0 === k ? 1 : 0 ; break ; case "n" : i = ( k + 1 ) % ( c . sortReset ? 3 : 2 ) ; break ; default : i = 0 } c . sortList . push ( [ f [ g ] [ 0 ] , i ] ) }
// sortBegin event triggered immediately before the sort
c . $table . trigger ( "sortBegin" , n ) ,
// setTimeout needed so the processing icon shows up
setTimeout ( function ( ) {
// set css for headers
b . setHeadersCss ( c ) , b . multisort ( c ) , b . appendCache ( c ) , c . $table . trigger ( "sortEnd" , n ) } , 1 ) } ,
// sort multiple columns
multisort : function ( a ) { /*jshint loopfunc:true */
var c , d , e , f , g = a . table , h = 0 , i = a . textSorter || "" , j = a . sortList , k = j . length , l = a . $tbodies . length ; if ( ! a . serverSideSorting && ! b . isEmptyObject ( a . cache ) ) { for ( a . debug && ( d = new Date ) , c = 0 ; l > c ; c ++ ) e = a . cache [ c ] . colMax , f = a . cache [ c ] . normalized , f . sort ( function ( c , d ) { var f , l , m , n , o , p , q ; for ( f = 0 ; k > f ; f ++ ) { if ( m = j [ f ] [ 0 ] , n = j [ f ] [ 1 ] , h = 0 === n , a . sortStable && c [ m ] === d [ m ] && 1 === k ) return c [ a . columns ] . order - d [ a . columns ] . order ; if ( l = /n/i . test ( b . getSortType ( a . parsers , m ) ) , l && a . strings [ m ] ? ( l = "boolean" == typeof b . string [ a . strings [ m ] ] ? ( h ? 1 : - 1 ) * ( b . string [ a . strings [ m ] ] ? - 1 : 1 ) : a . strings [ m ] ? b . string [ a . strings [ m ] ] || 0 : 0 , o = a . numberSorter ? a . numberSorter ( c [ m ] , d [ m ] , h , e [ m ] , g ) : b [ "sortNumeric" + ( h ? "Asc" : "Desc" ) ] ( c [ m ] , d [ m ] , l , e [ m ] , m , a ) ) : ( p = h ? c : d , q = h ? d : c , o = "function" == typeof i ? i ( p [ m ] , q [ m ] , h , m , g ) : "object" == typeof i && i . hasOwnProperty ( m ) ? i [ m ] ( p [ m ] , q [ m ] , h , m , g ) : b [ "sortNatural" + ( h ? "Asc" : "Desc" ) ] ( c [ m ] , d [ m ] , m , a ) ) , o ) return o } return c [ a . columns ] . order - d [ a . columns ] . order } ) ; a . debug && console . log ( "Applying sort " + j . toString ( ) + b . benchmark ( d ) ) } } , resortComplete : function ( b , c ) { b . table . isUpdating && b . $table . trigger ( "updateComplete" , b . table ) , a . isFunction ( c ) && c ( b . table ) } , checkResort : function ( c , d , e ) { var f = a . isArray ( d ) ? d : c . sortList ,
// if no resort parameter is passed, fallback to config.resort (true by default)
g = "undefined" == typeof d ? c . resort : d ;
// don't try to resort if the table is still processing
// this will catch spamming of the updateCell method
g === ! 1 || c . serverSideSorting || c . table . isProcessing ? ( b . resortComplete ( c , e ) , b . applyWidget ( c . table , ! 1 ) ) : f . length ? b . sortOn ( c , f , function ( ) { b . resortComplete ( c , e ) } , ! 0 ) : b . sortReset ( c , function ( ) { b . resortComplete ( c , e ) , b . applyWidget ( c . table , ! 1 ) } ) } , sortOn : function ( c , d , e , f ) { var g = c . table ; c . $table . trigger ( "sortStart" , g ) ,
// update header count index
b . updateHeaderSortCount ( c , d ) ,
// set css for headers
b . setHeadersCss ( c ) ,
// fixes #346
c . delayInit && b . isEmptyObject ( c . cache ) && b . buildCache ( c ) , c . $table . trigger ( "sortBegin" , g ) ,
// sort the table and append it to the dom
b . multisort ( c ) , b . appendCache ( c , f ) , c . $table . trigger ( "sortEnd" , g ) , b . applyWidget ( g ) , a . isFunction ( e ) && e ( g ) } , sortReset : function ( c , d ) { c . sortList = [ ] , b . setHeadersCss ( c ) , b . multisort ( c ) , b . appendCache ( c ) , a . isFunction ( d ) && d ( c . table ) } , getSortType : function ( a , b ) { return a && a [ b ] ? a [ b ] . type || "" : "" } , formatSortingOrder : function ( a ) {
// look for 'd' in 'desc' order; return true
return /^d/i . test ( a ) || 1 === a } ,
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
// I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall
sortNatural : function ( a , c ) { if ( a === c ) return 0 ; var d , e , f , g , h , i , j = b . regex ;
// first try and sort Hex codes
if ( j . hex . test ( c ) ) { if ( d = parseInt ( a . match ( j . hex ) , 16 ) , e = parseInt ( c . match ( j . hex ) , 16 ) , e > d ) return - 1 ; if ( d > e ) return 1 }
// natural sorting through split numeric strings and default strings
for ( d = a . replace ( j . chunk , "\\0$1\\0" ) . replace ( j . chunks , "" ) . split ( "\\0" ) , e = c . replace ( j . chunk , "\\0$1\\0" ) . replace ( j . chunks , "" ) . split ( "\\0" ) , i = Math . max ( d . length , e . length ) , h = 0 ; i > h ; h ++ ) {
// handle numeric vs string comparison - number < string - (Kyle Adams)
if ( f = isNaN ( d [ h ] ) ? d [ h ] || 0 : parseFloat ( d [ h ] ) || 0 , g = isNaN ( e [ h ] ) ? e [ h ] || 0 : parseFloat ( e [ h ] ) || 0 , isNaN ( f ) !== isNaN ( g ) ) return isNaN ( f ) ? 1 : - 1 ; if (
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
typeof f != typeof g && ( f += "" , g += "" ) , g > f ) return - 1 ; if ( f > g ) return 1 } return 0 } , sortNaturalAsc : function ( a , c , d , e ) { if ( a === c ) return 0 ; var f = b . string [ e . empties [ d ] || e . emptyTo ] ; return "" === a && 0 !== f ? "boolean" == typeof f ? f ? - 1 : 1 : - f || - 1 : "" === c && 0 !== f ? "boolean" == typeof f ? f ? 1 : - 1 : f || 1 : b . sortNatural ( a , c ) } , sortNaturalDesc : function ( a , c , d , e ) { if ( a === c ) return 0 ; var f = b . string [ e . empties [ d ] || e . emptyTo ] ; return "" === a && 0 !== f ? "boolean" == typeof f ? f ? - 1 : 1 : f || 1 : "" === c && 0 !== f ? "boolean" == typeof f ? f ? 1 : - 1 : - f || - 1 : b . sortNatural ( c , a ) } ,
// basic alphabetical sort
sortText : function ( a , b ) { return a > b ? 1 : b > a ? - 1 : 0 } ,
// return text string value by adding up ascii value
// so the text is somewhat sorted when using a digital sort
// this is NOT an alphanumeric sort
getTextValue : function ( a , b , c ) { if ( c ) {
// make sure the text value is greater than the max numerical value (max)
var d , e = a ? a . length : 0 , f = c + b ; for ( d = 0 ; e > d ; d ++ ) f += a . charCodeAt ( d ) ; return b * f } return 0 } , sortNumericAsc : function ( a , c , d , e , f , g ) { if ( a === c ) return 0 ; var h = b . string [ g . empties [ f ] || g . emptyTo ] ; return "" === a && 0 !== h ? "boolean" == typeof h ? h ? - 1 : 1 : - h || - 1 : "" === c && 0 !== h ? "boolean" == typeof h ? h ? 1 : - 1 : h || 1 : ( isNaN ( a ) && ( a = b . getTextValue ( a , d , e ) ) , isNaN ( c ) && ( c = b . getTextValue ( c , d , e ) ) , a - c ) } , sortNumericDesc : function ( a , c , d , e , f , g ) { if ( a === c ) return 0 ; var h = b . string [ g . empties [ f ] || g . emptyTo ] ; return "" === a && 0 !== h ? "boolean" == typeof h ? h ? - 1 : 1 : h || 1 : "" === c && 0 !== h ? "boolean" == typeof h ? h ? 1 : - 1 : - h || - 1 : ( isNaN ( a ) && ( a = b . getTextValue ( a , d , e ) ) , isNaN ( c ) && ( c = b . getTextValue ( c , d , e ) ) , c - a ) } , sortNumeric : function ( a , b ) { return a - b } , / *
█ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄ █ █ █ █ █ █ █ █ █ █ █ █ ▄ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ ▄ █ █ ▄ ▄ █ █ ▀ █ ▄
█ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ █ █ █ █ ▀ ▀ █ █ ▀ █ ▄
█ █ █ █ █ █ █ ▀ █ █ █ █ █ █ █ ▀ ▀ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀
* /
addWidget : function ( a ) { b . widgets . push ( a ) } , hasWidget : function ( b , c ) { return b = a ( b ) , b . length && b [ 0 ] . config && b [ 0 ] . config . widgetInit [ c ] || ! 1 } , getWidgetById : function ( a ) { var c , d , e = b . widgets . length ; for ( c = 0 ; e > c ; c ++ ) if ( d = b . widgets [ c ] , d && d . id && d . id . toLowerCase ( ) === a . toLowerCase ( ) ) return d } , applyWidgetOptions : function ( c ) { var d , e , f = c . config , g = f . widgets . length ; if ( g ) for ( d = 0 ; g > d ; d ++ ) e = b . getWidgetById ( f . widgets [ d ] ) , e && e . options && ( f . widgetOptions = a . extend ( ! 0 , { } , e . options , f . widgetOptions ) ) } , addWidgetFromClass : function ( a ) { var c , d , e = a . config ,
// look for widgets to apply from table class
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
f = "\\s" + e . widgetClass . replace ( b . regex . templateName , "([\\w-]+)" ) + "\\s" , g = new RegExp ( f , "g" ) ,
// extract out the widget id from the table class (widget id's can include dashes)
h = ( " " + e . table . className + " " ) . match ( g ) ; if ( h ) for ( c = h . length , d = 0 ; c > d ; d ++ ) e . widgets . push ( h [ d ] . replace ( g , "$1" ) ) } , applyWidget : function ( c , d , e ) { c = a ( c ) [ 0 ] ; // in case this is called externally
var f , g , h , i , j , k , l , m , n = c . config , o = [ ] ;
// prevent numerous consecutive widget applications
if ( d === ! 1 || ! c . hasInitialized || ! c . isApplyingWidgets && ! c . isUpdating ) { if ( n . debug && ( l = new Date ) , b . addWidgetFromClass ( c ) , n . widgets . length ) {
// build widget array & add priority as needed
for ( c . isApplyingWidgets = ! 0 ,
// ensure unique widget ids
n . widgets = a . grep ( n . widgets , function ( b , c ) { return a . inArray ( b , n . widgets ) === c } ) , h = n . widgets || [ ] , g = h . length , f = 0 ; g > f ; f ++ ) i = b . getWidgetById ( h [ f ] ) , i && i . id && ( i . priority || ( i . priority = 10 ) , o [ f ] = i ) ; for (
// sort widgets by priority
o . sort ( function ( a , b ) { return a . priority < b . priority ? - 1 : a . priority === b . priority ? 0 : 1 } ) , g = o . length , n . debug && console [ console . group ? "group" : "log" ] ( "Start " + ( d ? "initializing" : "applying" ) + " widgets" ) , f = 0 ; g > f ; f ++ ) i = o [ f ] , i && ( j = i . id , k = ! 1 , n . debug && ( m = new Date ) , ( d || ! n . widgetInit [ j ] ) && ( n . widgetInit [ j ] = ! 0 , c . hasInitialized && b . applyWidgetOptions ( c ) , "function" == typeof i . init && ( k = ! 0 , n . debug && console [ console . group ? "group" : "log" ] ( "Initializing " + j + " widget" ) , i . init ( c , i , c . config , c . config . widgetOptions ) ) ) , d || "function" != typeof i . format || ( k = ! 0 , n . debug && console [ console . group ? "group" : "log" ] ( "Updating " + j + " widget" ) , i . format ( c , c . config , c . config . widgetOptions , ! 1 ) ) , n . debug && k && ( console . log ( "Completed " + ( d ? "initializing " : "applying " ) + j + " widget" + b . benchmark ( m ) ) , console . groupEnd && console . groupEnd ( ) ) ) ; n . debug && console . groupEnd && console . groupEnd ( ) ,
// callback executed on init only
d || "function" != typeof e || e ( c ) } setTimeout ( function ( ) { c . isApplyingWidgets = ! 1 , a . data ( c , "lastWidgetApplication" , new Date ) , n . $table . trigger ( "tablesorter-ready" ) } , 0 ) , n . debug && ( i = n . widgets . length , console . log ( "Completed " + ( d === ! 0 ? "initializing " : "applying " ) + i + " widget" + ( 1 !== i ? "s" : "" ) + b . benchmark ( l ) ) ) } } , removeWidget : function ( c , d , e ) { c = a ( c ) [ 0 ] ; var f , g , h , i , j = c . config ;
// if name === true, add all widgets from $.tablesorter.widgets
if ( d === ! 0 ) for ( d = [ ] , i = b . widgets . length , h = 0 ; i > h ; h ++ ) g = b . widgets [ h ] , g && g . id && d . push ( g . id ) ; else
// name can be either an array of widgets names,
// or a space/comma separated list of widget names
d = ( a . isArray ( d ) ? d . join ( "," ) : d || "" ) . toLowerCase ( ) . split ( /[\s,]+/ ) ; for ( i = d . length , f = 0 ; i > f ; f ++ ) g = b . getWidgetById ( d [ f ] ) , h = a . inArray ( d [ f ] , j . widgets ) , g && g . remove && ( j . debug && console . log ( ( e ? "Refreshing" : "Removing" ) + ' "' + d [ f ] + '" widget' ) , g . remove ( c , j , j . widgetOptions , e ) , j . widgetInit [ d [ f ] ] = ! 1 ) , h >= 0 && e !== ! 0 && j . widgets . splice ( h , 1 ) } , refreshWidgets : function ( c , d , e ) { c = a ( c ) [ 0 ] ; // see issue #243
var f , g , h = c . config , i = h . widgets , j = b . widgets , k = j . length , l = [ ] , m = function ( b ) { a ( b ) . trigger ( "refreshComplete" ) } ;
// remove widgets not defined in config.widgets, unless doAll is true
for ( f = 0 ; k > f ; f ++ ) g = j [ f ] , g && g . id && ( d || a . inArray ( g . id , i ) < 0 ) && l . push ( g . id ) ; b . removeWidget ( c , l . join ( "," ) , ! 0 ) , e !== ! 0 ? (
// call widget init if
b . applyWidget ( c , d || ! 1 , m ) , d &&
// apply widget format
b . applyWidget ( c , ! 1 , m ) ) : m ( c ) } , / *
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ ▄ ▀ █ ▄
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ ▀ ▀ █ ▄
▀ █ █ █ █ ▀ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀
* /
benchmark : function ( a ) { return " ( " + ( ( new Date ) . getTime ( ) - a . getTime ( ) ) + "ms )" } ,
// deprecated ts.log
log : function ( ) { console . log ( arguments ) } ,
// $.isEmptyObject from jQuery v1.4
isEmptyObject : function ( a ) { /*jshint forin: false */
for ( var b in a ) return ! 1 ; return ! 0 } , isValueInArray : function ( a , b ) { var c , d = b && b . length || 0 ; for ( c = 0 ; d > c ; c ++ ) if ( b [ c ] [ 0 ] === a ) return c ; return - 1 } , formatFloat : function ( c , d ) { if ( "string" != typeof c || "" === c ) return c ;
// allow using formatFloat without a table; defaults to US number format
var e , f = d && d . config ? d . config . usNumberFormat !== ! 1 : "undefined" != typeof d ? d : ! 0 ;
// return the text instead of zero
// US Format - 1,234,567.89 -> 1234567.89
// make (#) into a negative number -> (10) = -10
return c = f ? c . replace ( b . regex . comma , "" ) : c . replace ( b . regex . digitNonUS , "" ) . replace ( b . regex . comma , "." ) , b . regex . digitNegativeTest . test ( c ) && ( c = c . replace ( b . regex . digitNegativeReplace , "-$1" ) ) , e = parseFloat ( c ) , isNaN ( e ) ? a . trim ( c ) : e } , isDigit : function ( a ) {
// replace all unwanted chars and match
return isNaN ( a ) ? b . regex . digitTest . test ( a . toString ( ) . replace ( b . regex . digitReplace , "" ) ) : "" !== a } ,
// computeTableHeaderCellIndexes from:
// http://www.javascripttoolbox.com/lib/table/examples.php
// http://www.javascripttoolbox.com/temp/table_cellindex.html
computeColumnIndex : function ( b ) { var c , d , e , f , g , h , i , j , k , l , m , n , o = [ ] , p = [ ] ; for ( c = 0 ; c < b . length ; c ++ ) for ( i = b [ c ] . cells , d = 0 ; d < i . length ; d ++ ) {
// Find first available column in the first row
for ( h = i [ d ] , g = a ( h ) , j = h . parentNode . rowIndex , k = j + "-" + g . index ( ) , l = h . rowSpan || 1 , m = h . colSpan || 1 , "undefined" == typeof o [ j ] && ( o [ j ] = [ ] ) , e = 0 ; e < o [ j ] . length + 1 ; e ++ ) if ( "undefined" == typeof o [ j ] [ e ] ) { n = e ; break } for (
// add data-column (setAttribute = IE8+)
h . setAttribute ? h . setAttribute ( "data-column" , n ) : g . attr ( "data-column" , n ) , e = j ; j + l > e ; e ++ ) for ( "undefined" == typeof o [ e ] && ( o [ e ] = [ ] ) , p = o [ e ] , f = n ; n + m > f ; f ++ ) p [ f ] = "x" } return p . length } ,
// automatically add a colgroup with col elements set to a percentage width
fixColumnWidth : function ( c ) { c = a ( c ) [ 0 ] ; var d , e , f , g , h , i = c . config , j = i . $table . children ( "colgroup" ) ; if (
// remove plugin-added colgroup, in case we need to refresh the widths
j . length && j . hasClass ( b . css . colgroup ) && j . remove ( ) , i . widthFixed && 0 === i . $table . children ( "colgroup" ) . length ) { for ( j = a ( '<colgroup class="' + b . css . colgroup + '">' ) , d = i . $table . width ( ) , f = i . $tbodies . find ( "tr:first" ) . children ( ":visible" ) , g = f . length , h = 0 ; g > h ; h ++ ) e = parseInt ( f . eq ( h ) . width ( ) / d * 1e3 , 10 ) / 10 + "%" , j . append ( a ( "<col>" ) . css ( "width" , e ) ) ; i . $table . prepend ( j ) } } ,
// get sorter, string, empty, etc options for each column from
// jQuery data, metadata, header option or header class name ('sorter-false')
// priority = jQuery data > meta > headers option > header class name
getData : function ( b , c , d ) { var e , f , g = "" , h = a ( b ) ;
// 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
// 'data-sort-initial-order' is assigned to 'sortInitialOrder'
// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
return h . length ? ( e = a . metadata ? h . metadata ( ) : ! 1 , f = " " + ( h . attr ( "class" ) || "" ) , "undefined" != typeof h . data ( d ) || "undefined" != typeof h . data ( d . toLowerCase ( ) ) ? g += h . data ( d ) || h . data ( d . toLowerCase ( ) ) : e && "undefined" != typeof e [ d ] ? g += e [ d ] : c && "undefined" != typeof c [ d ] ? g += c [ d ] : " " !== f && f . match ( " " + d + "-" ) && ( g = f . match ( new RegExp ( "\\s" + d + "-([\\w-]+)" ) ) [ 1 ] || "" ) , a . trim ( g ) ) : "" } , getColumnData : function ( b , c , d , e , f ) { if ( "undefined" != typeof c && null !== c ) { b = a ( b ) [ 0 ] ; var g , h , i = b . config , j = f || i . $headers ,
// c.$headerIndexed is not defined initially
k = i . $headerIndexed && i . $headerIndexed [ d ] || j . filter ( '[data-column="' + d + '"]:last' ) ; if ( c [ d ] ) return e ? c [ d ] : c [ j . index ( k ) ] ; for ( h in c ) if ( "string" == typeof h && ( g = k . filter ( h ) . add ( k . find ( h ) ) , g . length ) ) return c [ h ] } } ,
// *** Process table ***
// add processing indicator
isProcessing : function ( c , d , e ) { c = a ( c ) ; var f = c [ 0 ] . config ,
// default to all headers
g = e || c . find ( "." + b . css . header ) ; d ? (
// don't use sortList if custom $ths used
"undefined" != typeof e && f . sortList . length > 0 && (
// get headers from the sortList
g = g . filter ( function ( ) {
// get data-column from attr to keep compatibility with jQuery 1.2.6
return this . sortDisabled ? ! 1 : b . isValueInArray ( parseFloat ( a ( this ) . attr ( "data-column" ) ) , f . sortList ) >= 0 } ) ) , c . add ( g ) . addClass ( b . css . processing + " " + f . cssProcessing ) ) : c . add ( g ) . removeClass ( b . css . processing + " " + f . cssProcessing ) } ,
// detach tbody but save the position
// don't use tbody because there are portions that look for a tbody index (updateCell)
processTbody : function ( b , c , d ) { if ( b = a ( b ) [ 0 ] , d ) return b . isProcessing = ! 0 , c . before ( '<colgroup class="tablesorter-savemyplace"/>' ) , a . fn . detach ? c . detach ( ) : c . remove ( ) ; var e = a ( b ) . find ( "colgroup.tablesorter-savemyplace" ) ; c . insertAfter ( e ) , e . remove ( ) , b . isProcessing = ! 1 } , clearTableBody : function ( b ) { a ( b ) [ 0 ] . config . $tbodies . children ( ) . detach ( ) } ,
// used when replacing accented characters during sorting
characterEquivalents : { a : "áàâãäąå" , // áàâãäąå
A : "ÁÀÂÃÄĄÅ" , // ÁÀÂÃÄĄÅ
c : "çćč" , // çćč
C : "ÇĆČ" , // ÇĆČ
e : "éèêëěę" , // éèêëěę
E : "ÉÈÊËĚĘ" , // ÉÈÊËĚĘ
i : "íìİîïı" , // íìİîïı
I : "ÍÌİÎÏ" , // ÍÌİÎÏ
o : "óòôõöō" , // óòôõöō
O : "ÓÒÔÕÖŌ" , // ÓÒÔÕÖŌ
ss : "ß" , // ß (s sharp)
SS : "ẞ" , // ẞ (Capital sharp s)
u : "úùûüů" , // úùûüů
U : "ÚÙÛÜŮ" } , replaceAccents : function ( a ) { var c , d = "[" , e = b . characterEquivalents ; if ( ! b . characterRegex ) { b . characterRegexArray = { } ; for ( c in e ) "string" == typeof c && ( d += e [ c ] , b . characterRegexArray [ c ] = new RegExp ( "[" + e [ c ] + "]" , "g" ) ) ; b . characterRegex = new RegExp ( d + "]" ) } if ( b . characterRegex . test ( a ) ) for ( c in e ) "string" == typeof c && ( a = a . replace ( b . characterRegexArray [ c ] , c ) ) ; return a } ,
// restore headers
restoreHeaders : function ( c ) { var d , e , f = a ( c ) [ 0 ] . config , g = f . $table . find ( f . selectorHeaders ) , h = g . length ;
// don't use c.$headers here in case header cells were swapped
for ( d = 0 ; h > d ; d ++ ) e = g . eq ( d ) , e . find ( "." + b . css . headerIn ) . length && e . html ( f . headerContent [ d ] ) } , destroy : function ( c , d , e ) { if ( c = a ( c ) [ 0 ] , c . hasInitialized ) {
// remove all widgets
b . removeWidget ( c , ! 0 , ! 1 ) ; var f , g = a ( c ) , h = c . config , i = h . debug , j = g . find ( "thead:first" ) , k = j . find ( "tr." + b . css . headerRow ) . removeClass ( b . css . headerRow + " " + h . cssHeaderRow ) , l = g . find ( "tfoot:first > tr" ) . children ( "th, td" ) ; d === ! 1 && a . inArray ( "uitheme" , h . widgets ) >= 0 && (
// reapply uitheme classes, in case we want to maintain appearance
g . trigger ( "applyWidgetId" , [ "uitheme" ] ) , g . trigger ( "applyWidgetId" , [ "zebra" ] ) ) ,
// remove widget added rows, just in case
j . find ( "tr" ) . not ( k ) . remove ( ) ,
// disable tablesorter
f = "sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress " + "sortBegin sortEnd resetToLoadState " . split ( " " ) . join ( h . namespace + " " ) , g . removeData ( "tablesorter" ) . unbind ( f . replace ( b . regex . spaces , " " ) ) , h . $headers . add ( l ) . removeClass ( [ b . css . header , h . cssHeader , h . cssAsc , h . cssDesc , b . css . sortAsc , b . css . sortDesc , b . css . sortNone ] . join ( " " ) ) . removeAttr ( "data-column" ) . removeAttr ( "aria-label" ) . attr ( "aria-disabled" , "true" ) , k . find ( h . selectorSort ) . unbind ( "mousedown mouseup keypress " . split ( " " ) . join ( h . namespace + " " ) . replace ( b . regex . spaces , " " ) ) , b . restoreHeaders ( c ) , g . toggleClass ( b . css . table + " " + h . tableClass + " tablesorter-" + h . theme , d === ! 1 ) ,
// clear flag in case the plugin is initialized again
c . hasInitialized = ! 1 , delete c . config . cache , "function" == typeof e && e ( c ) , i && console . log ( "tablesorter has been removed" ) } } } ; a . fn . tablesorter = function ( c ) { return this . each ( function ( ) { var d = this ,
// merge & extend config options
e = a . extend ( ! 0 , { } , b . defaults , c , b . instanceMethods ) ;
// save initial settings
e . originalSettings = c ,
// create a table from data (build table widget)
! d . hasInitialized && b . buildTable && "TABLE" !== this . nodeName ?
// return the table (in case the original target is the table's container)
b . buildTable ( d , e ) : b . setup ( d , e ) } ) } ,
// set up debug logs
window . console && window . console . log || (
// access $.tablesorter.logs for browsers that don't have a console...
b . logs = [ ] , /*jshint -W020 */
console = { } , console . log = console . warn = console . error = console . table = function ( ) { var a = arguments . length > 1 ? arguments : arguments [ 0 ] ; b . logs . push ( { date : Date . now ( ) , log : a } ) } ) ,
// add default parsers
b . addParser ( { id : "no-parser" , is : function ( ) { return ! 1 } , format : function ( ) { return "" } , type : "text" } ) , b . addParser ( { id : "text" , is : function ( ) { return ! 0 } , format : function ( c , d ) { var e = d . config ; return c && ( c = a . trim ( e . ignoreCase ? c . toLocaleLowerCase ( ) : c ) , c = e . sortLocaleCompare ? b . replaceAccents ( c ) : c ) , c } , type : "text" } ) , b . regex . nondigit = /[^\w,. \-()]/g , b . addParser ( { id : "digit" , is : function ( a ) { return b . isDigit ( a ) } , format : function ( c , d ) { var e = b . formatFloat ( ( c || "" ) . replace ( b . regex . nondigit , "" ) , d ) ; return c && "number" == typeof e ? e : c ? a . trim ( c && d . config . ignoreCase ? c . toLocaleLowerCase ( ) : c ) : c } , type : "numeric" } ) , b . regex . currencyReplace = /[+\-,. ]/g , b . regex . currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/ , b . addParser ( { id : "currency" , is : function ( a ) {
// test for £$€¤¥¢
return a = ( a || "" ) . replace ( b . regex . currencyReplace , "" ) , b . regex . currencyTest . test ( a ) } , format : function ( c , d ) { var e = b . formatFloat ( ( c || "" ) . replace ( b . regex . nondigit , "" ) , d ) ; return c && "number" == typeof e ? e : c ? a . trim ( c && d . config . ignoreCase ? c . toLocaleLowerCase ( ) : c ) : c } , type : "numeric" } ) ,
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
// now, this regex can be updated before initialization
b . regex . urlProtocolTest = /^(https?|ftp|file):\/\// , b . regex . urlProtocolReplace = /(https?|ftp|file):\/\// , b . addParser ( { id : "url" , is : function ( a ) { return b . regex . urlProtocolTest . test ( a ) } , format : function ( c ) { return c ? a . trim ( c . replace ( b . regex . urlProtocolReplace , "" ) ) : c } , parsed : ! 0 , // filter widget flag
type : "text" } ) , b . regex . dash = /-/g , b . regex . isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/ , b . addParser ( { id : "isoDate" , is : function ( a ) { return b . regex . isoDate . test ( a ) } , format : function ( a , c ) { var d = a ? new Date ( a . replace ( b . regex . dash , "/" ) ) : a ; return d instanceof Date && isFinite ( d ) ? d . getTime ( ) : a } , type : "numeric" } ) , b . regex . percent = /%/g , b . regex . percentTest = /(\d\s*?%|%\s*?\d)/ , b . addParser ( { id : "percent" , is : function ( a ) { return b . regex . percentTest . test ( a ) && a . length < 15 } , format : function ( a , c ) { return a ? b . formatFloat ( a . replace ( b . regex . percent , "" ) , c ) : a } , type : "numeric" } ) ,
// added image parser to core v2.17.9
b . addParser ( { id : "image" , is : function ( a , b , c , d ) { return d . find ( "img" ) . length > 0 } , format : function ( b , c , d ) { return a ( d ) . find ( "img" ) . attr ( c . config . imgAttr || "alt" ) || b } , parsed : ! 0 , // filter widget flag
type : "text" } ) , b . regex . dateReplace = /(\S)([AP]M)$/i , // used by usLongDate & time parser
b . regex . usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i , b . regex . usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i , b . addParser ( { id : "usLongDate" , is : function ( a ) {
// two digit years are not allowed cross-browser
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
return b . regex . usLongDateTest1 . test ( a ) || b . regex . usLongDateTest2 . test ( a ) } , format : function ( a , c ) { var d = a ? new Date ( a . replace ( b . regex . dateReplace , "$1 $2" ) ) : a ; return d instanceof Date && isFinite ( d ) ? d . getTime ( ) : a } , type : "numeric" } ) ,
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
b . regex . shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/ ,
// escaped "-" because JSHint in Firefox was showing it as an error
b . regex . shortDateReplace = /[\-.,]/g ,
// XXY covers MDY & DMY formats
2015-11-02 16:50:31 +00:00
b . regex . shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/ , b . regex . shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/ , b . convertFormat = function ( a , c ) { a = ( a || "" ) . replace ( b . regex . spaces , " " ) . replace ( b . regex . shortDateReplace , "/" ) , "mmddyyyy" === c ? a = a . replace ( b . regex . shortDateXXY , "$3/$1/$2" ) : "ddmmyyyy" === c ? a = a . replace ( b . regex . shortDateXXY , "$3/$2/$1" ) : "yyyymmdd" === c && ( a = a . replace ( b . regex . shortDateYMD , "$1/$2/$3" ) ) ; var d = new Date ( a ) ; return d instanceof Date && isFinite ( d ) ? d . getTime ( ) : "" } , b . addParser ( { id : "shortDate" , // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
is : function ( a ) { return a = ( a || "" ) . replace ( b . regex . spaces , " " ) . replace ( b . regex . shortDateReplace , "/" ) , b . regex . shortDateTest . test ( a ) } , format : function ( a , c , d , e ) { if ( a ) { var f = c . config , g = f . $headerIndexed [ e ] , h = g . length && g . data ( "dateFormat" ) || b . getData ( g , b . getColumnData ( c , f . headers , e ) , "dateFormat" ) || f . dateFormat ;
// save format because getData can be slow...
return g . length && g . data ( "dateFormat" , h ) , b . convertFormat ( a , h ) || a } return a } , type : "numeric" } ) ,
// match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tk
b . regex . timeTest = /^([1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)$/i , b . regex . timeMatch = /([1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i , b . addParser ( { id : "time" , is : function ( a ) { return b . regex . timeTest . test ( a ) } , format : function ( a , c ) {
// isolate time... ignore month, day and year
var d , e = ( a || "" ) . match ( b . regex . timeMatch ) , f = new Date ( a ) ,
// no time component? default to 00:00 by leaving it out, but only if str is defined
g = a && ( null !== e ? e [ 0 ] : "00:00 AM" ) , h = g ? new Date ( "2000/01/01 " + g . replace ( b . regex . dateReplace , "$1 $2" ) ) : g ; return h instanceof Date && isFinite ( h ) ? ( d = f instanceof Date && isFinite ( f ) ? f . getTime ( ) : 0 , d ? parseFloat ( h . getTime ( ) + "." + f . getTime ( ) ) : h . getTime ( ) ) : a } , type : "numeric" } ) , b . addParser ( { id : "metadata" , is : function ( ) { return ! 1 } , format : function ( b , c , d ) { var e = c . config , f = e . parserMetadataName ? e . parserMetadataName : "sortValue" ; return a ( d ) . metadata ( ) [ f ] } , type : "numeric" } ) , / *
2015-10-31 15:08:21 +00:00
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄
▄ █ ▀ █ █ ▄ ▄ █ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █
▄ █ ▀ █ █ ▀ ▀ █ █ ▀ ▀ █ █ █ █ ▀ ▀ █ █ █ ▀ ▀ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ █ █ █ █ █ █ █ █
* /
// add default widgets
b . addWidget ( { id : "zebra" , priority : 90 , format : function ( b , c , d ) { var e , f , g , h , i , j , k , l = new RegExp ( c . cssChildRow , "i" ) , m = c . $tbodies . add ( a ( c . namespace + "_extra_table" ) . children ( "tbody:not(." + c . cssInfoBlock + ")" ) ) ; for ( i = 0 ; i < m . length ; i ++ ) for ( g = 0 , e = m . eq ( i ) . children ( "tr:visible" ) . not ( c . selectorRemove ) , k = e . length , j = 0 ; k > j ; j ++ ) f = e . eq ( j ) , l . test ( f [ 0 ] . className ) || g ++ , h = g % 2 === 0 , f . removeClass ( d . zebra [ h ? 1 : 0 ] ) . addClass ( d . zebra [ h ? 0 : 1 ] ) } , remove : function ( a , c , d , e ) { if ( ! e ) { var f , g , h = c . $tbodies , i = ( d . zebra || [ "even" , "odd" ] ) . join ( " " ) ; for ( f = 0 ; f < h . length ; f ++ ) g = b . processTbody ( a , h . eq ( f ) , ! 0 ) , g . children ( ) . removeClass ( i ) , b . processTbody ( a , g , ! 1 ) } } } ) } ( jQuery ) , 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
2015-11-05 02:15:37 +00:00
// convert filters to strings (maybe not the best method)- see #1070
2015-10-31 15:08:21 +00:00
// give it time for the processing icon to kick in
2015-11-05 02:15:37 +00:00
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 = [ ] ) , k = k . join ( "\x00" ) . split ( "\x00" ) , 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 ) {
2015-10-31 15:08:21 +00:00
// 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
2015-11-05 02:15:37 +00:00
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 "undefined" == typeof f && ( f = ! 0 ) , 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
2015-10-31 15:08:21 +00:00
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
2015-11-05 02:15:37 +00:00
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 ) ; c . resizable . setHandlePosition ( b , d ) , c . resizable . bindings ( b , d ) } } , 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 ) {
2015-10-31 15:08:21 +00:00
// 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
2015-11-05 02:15:37 +00:00
toggleTextSelection : function ( b , d , e ) { var f = b . namespace + "tsresize" ; d . resizable _vars . disabled = e , a ( "body" ) . toggleClass ( c . css . resizableNoSelect , e ) , e ? a ( "body" ) . attr ( "unselectable" , "on" ) . bind ( "selectstart" + f , ! 1 ) : a ( "body" ) . removeAttr ( "unselectable" ) . unbind ( "selectstart" + f ) } , bindings : function ( d , e ) { var f = d . namespace + "tsresize" ; e . $resizable _container . children ( ) . bind ( "mousedown" , function ( b ) {
2015-10-31 15:08:21 +00:00
// save header cell and mouse position
2015-11-05 02:15:37 +00:00
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 , e , ! 0 ) } ) , a ( document ) . bind ( "mousemove" + f , function ( a ) { var b = e . resizable _vars ;
2015-10-31 15:08:21 +00:00
// ignore mousemove if no mousedown
2015-11-05 02:15:37 +00:00
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 , e , ! 1 ) , c . resizable . stopResize ( d , e ) , c . resizable . setHandlePosition ( d , e ) ) } ) ,
2015-10-31 15:08:21 +00:00
// 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
2015-11-05 02:15:37 +00:00
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 , e , ! 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 (
2015-10-31 15:08:21 +00:00
// 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 } ) ;