2015-10-31 16:06:09 +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.0" , 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!
if ( 2 !== l [ f ] [ 1 ] && ( d = c . $headers . filter ( function ( d , e ) { for (
// only include headers that are in the sortList (this includes colspans)
var f = ! 0 , g = a ( e ) , h = parseInt ( g . attr ( "data-column" ) , 10 ) , i = h + e . colSpan ; i > h ; h ++ ) f = f ? b . isValueInArray ( h , c . sortList ) > - 1 : ! 1 ; return f } ) , 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 ] ] ) ;
// 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
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 . is ( "." + b . css . sortDesc + ",." + b . css . sortAsc ) || ( c . sortVars [ p ] . count = - 1 ) ;
// 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
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 . 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 , g , h = c . config , i = h . $headerIndexed [ e ] , j = i . length && i [ 0 ] . dateFormat || b . getData ( i , b . getColumnData ( c , h . headers , e ) , "dateFormat" ) || h . dateFormat ; return g = a . replace ( b . regex . spaces , " " ) . replace ( b . regex . shortDateReplace , "/" ) , "mmddyyyy" === j ? g = g . replace ( b . regex . shortDateXXY , "$3/$1/$2" ) : "ddmmyyyy" === j ? g = g . replace ( b . regex . shortDateXXY , "$3/$2/$1" ) : "yyyymmdd" === j && ( g = g . replace ( b . regex . shortDateYMD , "$1/$2/$3" ) ) , f = new Date ( g ) , f instanceof Date && isFinite ( f ) ? f . getTime ( ) : a } return a } , type : "numeric" } ) , b . regex . timeTest = /^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i , b . addParser ( { id : "time" , is : function ( a ) { return b . regex . timeTest . test ( a ) } , format : function ( a , c ) { var d = a ? new Date ( "2000/01/01 " + a . replace ( b . regex . dateReplace , "$1 $2" ) ) : a ; return d instanceof Date && isFinite ( d ) ? d . 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" } ) , / *
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▄ █ █ █ █ █ ▄ ▄ █ █ █ █ ▄
▄ █ ▀ █ █ ▄ ▄ █ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █ █ █ ▄ ▄ █ █
▄ █ ▀ █ █ ▀ ▀ █ █ ▀ ▀ █ █ █ █ ▀ ▀ █ █ █ ▀ ▀ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▀ █ █ █ █ █ █ █ █
* /
// 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 ) , a . tablesorter } ) ;