2015-10-31 16:06:09 +00:00
/*! Widget: math - updated 10/31/2015 (v2.24.0) */
2015-10-31 15:08:21 +00:00
/ *
* Requires tablesorter v2 . 16 + and jQuery 1.7 +
* by Rob Garrison
* /
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
! function ( a ) { "use strict" ; var b = a . tablesorter , c = { error : { 0 : "Infinity result: Divide by zero" , 1 : "Need more than one element to make this calculation" , undef : "No elements found" } ,
// value returned when calculation is not possible, e.g. no values, dividing by zero, etc.
invalid : function ( a , b , d ) {
// name = function returning invalid results
// errorIndex = math.error index with an explanation of the error
return console . log ( b , c . error [ d ] ) , a && a . widgetOptions . math _none || "none" } , events : "tablesorter-initialized update updateAll updateRows addRows updateCell filterReset filterEnd " . split ( " " ) . join ( ".tsmath " ) , processText : function ( a , c ) { var d = c . attr ( a . textAttribute ) ;
// isNaN('') => false
return "undefined" == typeof d && ( d = c [ 0 ] . textContent || c . text ( ) ) , d = b . formatFloat ( d . replace ( /[^\w,. \-()]/g , "" ) , a . table ) || 0 , isNaN ( d ) ? 0 : d } ,
// get all of the row numerical values in an arry
getRow : function ( b , d ) { var e = b . widgetOptions , f = [ ] , g = d . closest ( "tr" ) , h = g . children ( ) . not ( "[" + e . math _dataAttrib + "=ignore]" ) ; return g . hasClass ( e . filter _filteredRow || "filtered" ) || ( e . math _ignore . length && ( h = h . not ( "[data-column=" + e . math _ignore . join ( "],[data-column=" ) + "]" ) ) , f = h . not ( d ) . map ( function ( ) { return c . processText ( b , a ( this ) ) } ) . get ( ) ) , f } ,
// get all of the column numerical values in an arry
getColumn : function ( a , b , d ) { var e , f , g , h , i , j = [ ] , k = a . widgetOptions , l = k . math _dataAttrib , m = k . filter _filteredRow || "filtered" , n = parseInt ( b . attr ( "data-column" ) , 10 ) , o = a . $table . children ( "tbody" ) . children ( ) , p = b . closest ( "tr" ) ;
// make sure tfoot rows are AFTER the tbody rows
// $rows.add( c.$table.children( 'tfoot' ).children() );
if ( "above" === d ) for ( g = o . index ( p ) , e = g ; e >= 0 ; ) f = o . eq ( e ) . children ( ) . filter ( "[data-column=" + n + "]" ) , i = f . filter ( "[" + l + "^=above]" ) . length , ( ! o . eq ( e ) . hasClass ( m ) && o . eq ( e ) . not ( "[" + l + "=ignore]" ) . length && e !== g || i && e !== g ) && ( i ? e = 0 : f . length && j . push ( c . processText ( a , f ) ) ) , e -- ; else if ( "below" === d )
// index + 1 to ignore starting node
for ( g = o . length , e = o . index ( p ) + 1 ; g > e && ( f = o . eq ( e ) . children ( ) . filter ( "[data-column=" + n + "]" ) , ! f . filter ( "[" + l + "^=below]" ) . length ) ; e ++ ) ! o . eq ( e ) . hasClass ( m ) && o . eq ( e ) . not ( "[" + l + "=ignore]" ) . length && f . length && j . push ( c . processText ( a , f ) ) ; else for ( h = o . not ( "[" + l + "=ignore]" ) , g = h . length , e = 0 ; g > e ; e ++ ) f = h . eq ( e ) . children ( ) . filter ( "[data-column=" + n + "]" ) , h . eq ( e ) . hasClass ( m ) || ! f . not ( "[" + l + "^=above],[" + l + "^=below],[" + l + "^=col]" ) . length || f . is ( b ) || j . push ( c . processText ( a , f ) ) ; return j } ,
// get all of the column numerical values in an arry
getAll : function ( b ) { var d , e , f , g , h , i , j , k , l = [ ] , m = b . widgetOptions , n = m . math _dataAttrib , o = m . filter _filteredRow || "filtered" , p = b . $table . children ( "tbody" ) . children ( ) . not ( "[" + n + "=ignore]" ) ; for ( h = p . length , g = 0 ; h > g ; g ++ ) if ( f = p . eq ( g ) , ! f . hasClass ( o ) )
// $row.children().each(function(){
for ( i = f . children ( ) . not ( "[" + n + "=ignore]" ) , k = i . length , j = 0 ; k > j ; j ++ ) d = i . eq ( j ) , e = parseInt ( d . attr ( "data-column" ) , 10 ) , ! d . filter ( "[" + n + "]" ) . length && a . inArray ( e , m . math _ignore ) < 0 && l . push ( c . processText ( b , d ) ) ; return l } , setColumnIndexes : function ( c ) { c . $table . after ( '<div id="_tablesorter_table_placeholder"></div>' ) ;
// detach table from DOM to speed up column indexing
var d = c . $table . detach ( ) ; b . computeColumnIndex ( d . children ( "tbody" ) . children ( ) ) , a ( "#_tablesorter_table_placeholder" ) . after ( d ) . remove ( ) } , recalculate : function ( a , d , e ) { if ( a && ( ! d . math _isUpdating || e ) ) { var f , g , h ; a . debug && ( f = new Date ) ,
// add data-column attributes to all table cells
e && c . setColumnIndexes ( a ) ,
// data-attribute name (defaults to data-math)
d . math _dataAttrib = "data-" + ( d . math _data || "math" ) ,
// all non-info tbody cells
g = d . math _dataAttrib , h = a . $tbodies . find ( "[" + g + "]" ) , c . mathType ( a , h , d . math _priority ) ,
// only info tbody cells
h = a . $table . children ( "." + a . cssInfoBlock + ", tfoot" ) . find ( "[" + g + "]" ) , c . mathType ( a , h , d . math _priority ) ,
// find the 'all' total
h = a . $table . find ( "[" + g + "^=all]" ) , c . mathType ( a , h , [ "all" ] ) , d . math _isUpdating = ! 0 , a . debug && console [ console . group ? "group" : "log" ] ( "Math widget triggering an update after recalculation" ) ,
// update internal cache
b . update ( a ) , a . debug && console . log ( "Math widget update completed" + b . benchmark ( f ) ) } } , mathType : function ( d , e , f ) { if ( e . length ) { var g , h , i , j , k , l , m , n , o = d . widgetOptions , p = o . math _dataAttrib , q = b . equations ; "all" === f [ 0 ] && (
// no need to get all cells more than once
k = c . getAll ( d ) ) , d . debug && console [ console . group ? "group" : "log" ] ( "Tablesorter Math widget recalculation" ) ,
// $.each is okay here... only 4 priorities
a . each ( f , function ( a , b ) { if ( l = e . filter ( "[" + p + "^=" + b + "]" ) , n = l . length ) { for ( d . debug && console [ console . group ? "group" : "log" ] ( b ) , m = 0 ; n > m ; m ++ ) i = l . eq ( m ) , i . parent ( ) . hasClass ( o . filter _filteredRow || "filtered" ) || ( g = ( i . attr ( p ) || "" ) . replace ( b + "-" , "" ) , j = "row" === b ? c . getRow ( d , i ) : "all" === b ? k : c . getColumn ( d , i , b ) , q [ g ] && ( j . length ? ( h = q [ g ] ( j , d ) , d . debug && console . log ( i . attr ( p ) , j , "=" , h ) ) : h = c . invalid ( d , g , "mean" === g ? 0 : "undef" ) , c . output ( i , o , h , j ) ) ) ; d . debug && console . groupEnd && console . groupEnd ( ) } } ) , d . debug && console . groupEnd && console . groupEnd ( ) } } , output : function ( a , c , d , e ) {
// get mask from cell data-attribute: data-math-mask="#,##0.00"
var f = a . attr ( "data-" + c . math _data + "-mask" ) || c . math _mask , g = b . formatMask ( f , d , c . math _wrapPrefix , c . math _wrapSuffix ) ; "function" == typeof c . math _complete && ( g = c . math _complete ( a , c , g , d , e ) ) , g !== ! 1 && a . html ( g ) } } ;
// Modified from https://code.google.com/p/javascript-number-formatter/
/ * *
2015-02-13 04:13:45 +00:00
* @ preserve IntegraXor Web SCADA - JavaScript Number Formatter
* http : // www.integraxor.com/
* author : KPL , KHL
* ( c ) 2011 ecava
* Dual licensed under the MIT or GPL Version 2 licenses .
* /
2015-10-31 15:08:21 +00:00
b . formatMask = function ( a , b , c , d ) { if ( ! a || isNaN ( + b ) ) return b ; var e , f , g , h , i , j , k , l , m , n , o , p , q , r , s , t = "" ,
// find prefix/suffix
u = a . length , v = a . search ( /[0-9\-\+#]/ ) , w = v > 0 ? a . substring ( 0 , v ) : "" , x = w ; if ( v > 0 && c && ( x = /\{content\}/ . test ( c || "" ) ? ( c || "" ) . replace ( /\{content\}/g , w || "" ) : ( c || "" ) + w ) , s = a . split ( "" ) . reverse ( ) . join ( "" ) , r = s . search ( /[0-9\-\+#]/ ) , q = u - r , q += "." === a . substring ( q , q + 1 ) ? 1 : 0 , w = r > 0 ? a . substring ( q , u ) : "" , t = w , "" !== w && d && ( t = /\{content\}/ . test ( d || "" ) ? ( d || "" ) . replace ( /\{content\}/g , w || "" ) : w + ( d || "" ) ) , a = a . substring ( v , q ) , b = "-" == a . charAt ( 0 ) ? - b : + b , e = 0 > b ? b = - b : 0 , f = a . match ( /[^\d\-\+#]/g ) , g = f && f [ f . length - 1 ] || "." , h = f && f [ 1 ] && f [ 0 ] || "," , a = a . split ( g ) , b = b . toFixed ( a [ 1 ] && a [ 1 ] . length ) , b = + b + "" , j = a [ 1 ] && a [ 1 ] . lastIndexOf ( "0" ) , l = b . split ( "." ) , ( ! l [ 1 ] || l [ 1 ] && l [ 1 ] . length <= j ) && ( b = ( + b ) . toFixed ( j + 1 ) ) , m = a [ 0 ] . split ( h ) , a [ 0 ] = m . join ( "" ) , i = a [ 0 ] && a [ 0 ] . indexOf ( "0" ) , i > - 1 ) for ( ; l [ 0 ] . length < a [ 0 ] . length - i ; ) l [ 0 ] = "0" + l [ 0 ] ; else 0 === + l [ 0 ] && ( l [ 0 ] = "" ) ; if ( b = b . split ( "." ) , b [ 0 ] = l [ 0 ] , k = m [ 1 ] && m [ m . length - 1 ] . length ) { for ( n = b [ 0 ] , o = "" , p = n . length % k , u = n . length , q = 0 ; u > q ; q ++ ) o += n . charAt ( q ) , ! ( ( q - p + 1 ) % k ) && u - k > q && ( o += h ) ; b [ 0 ] = o }
// put back any negation, combine integer and fraction, and add back prefix & suffix
return b [ 1 ] = a [ 1 ] && b [ 1 ] ? g + b [ 1 ] : "" , x + ( ( e ? "-" : "" ) + b [ 0 ] + b [ 1 ] ) + t } , b . equations = { count : function ( a ) { return a . length } , sum : function ( a ) { var b , c = a . length , d = 0 ; for ( b = 0 ; c > b ; b ++ ) d += a [ b ] ; return d } , mean : function ( a ) { var c = b . equations . sum ( a ) ; return c / a . length } , median : function ( a , b ) { var d , e = a . length ;
// https://gist.github.com/caseyjustus/1166258
return e > 1 ? ( a . sort ( function ( a , b ) { return a - b } ) , d = Math . floor ( e / 2 ) , e % 2 ? a [ d ] : ( a [ d - 1 ] + a [ d ] ) / 2 ) : c . invalid ( b , "median" , 1 ) } , mode : function ( a ) {
// http://stackoverflow.com/a/3451640/145346
var b , c , d , e = { } , f = 1 , g = [ a [ 0 ] ] ; for ( b = 0 ; b < a . length ; b ++ ) c = a [ b ] , e [ c ] = e [ c ] ? e [ c ] + 1 : 1 , d = e [ c ] , d > f ? ( g = [ c ] , f = d ) : d === f && ( g . push ( c ) , f = d ) ;
// returns arry of modes if there is a tie
return g . sort ( function ( a , b ) { return a - b } ) } , max : function ( a ) { return Math . max . apply ( Math , a ) } , min : function ( a ) { return Math . min . apply ( Math , a ) } , range : function ( a ) { var b = a . sort ( function ( a , b ) { return a - b } ) ; return b [ a . length - 1 ] - b [ 0 ] } ,
// common variance equation
// (not accessible via data-attribute setting)
variance : function ( a , d , e ) { for ( var f , g = b . equations . mean ( a ) , h = 0 , i = a . length ; i -- ; ) h += Math . pow ( a [ i ] - g , 2 ) ; return f = a . length - ( d ? 0 : 1 ) , 0 === f ? c . invalid ( e , "variance" , 0 ) : h /= f } ,
// variance (population)
varp : function ( a , c ) { return b . equations . variance ( a , ! 0 , c ) } ,
// variance (sample)
vars : function ( a , c ) { return b . equations . variance ( a , ! 1 , c ) } ,
// standard deviation (sample)
stdevs : function ( a , c ) { var d = b . equations . variance ( a , ! 1 , c ) ; return Math . sqrt ( d ) } ,
// standard deviation (population)
stdevp : function ( a , c ) { var d = b . equations . variance ( a , ! 0 , c ) ; return Math . sqrt ( d ) } } ,
// add new widget called repeatHeaders
// ************************************
b . addWidget ( { id : "math" , priority : 100 , options : { math _data : "math" ,
// column index to ignore
math _ignore : [ ] ,
// mask info: https://code.google.com/p/javascript-number-formatter/
math _mask : "#,##0.00" ,
// complete executed after each fucntion
math _complete : null , // function($cell, wo, result, value, arry){ return result; },
// order of calculation; 'all' is last
math _priority : [ "row" , "above" , "below" , "col" ] ,
// template for or just prepend the mask prefix & suffix with this HTML
// e.g. '<span class="red">{content}</span>'
math _prefix : "" , math _suffix : "" ,
// no matching math elements found (text added to cell)
math _none : "N/A" , math _event : "recalculate" } , init : function ( a , d , e , f ) {
// filterEnd fires after updateComplete
var g = b . hasWidget ( a , "filter" ) ? "filterEnd" : "updateComplete" ; e . $table . off ( ( c . events + " updateComplete.tsmath " + f . math _event ) . replace ( /\s+/g , " " ) ) . on ( c . events + " " + f . math _event , function ( a ) { var b = "tablesorter-initialized" === a . type ; ( ! f . math _isUpdating || b ) && ( /filter/ . test ( a . type ) ||
// redo data-column indexes on update
c . setColumnIndexes ( e ) , c . recalculate ( e , f , b ) ) } ) . on ( g + ".tsmath" , function ( ) { setTimeout ( function ( ) { f . math _isUpdating && e . debug && console . groupEnd && console . groupEnd ( ) , f . math _isUpdating = ! 1 } , 40 ) } ) , f . math _isUpdating = ! 1 ,
// math widget initialized after table - see #946
a . hasInitialized && c . recalculate ( e , f , ! 0 ) } ,
// this remove function is called when using the refreshWidgets method or when destroying the tablesorter plugin
// this function only applies to tablesorter v2.4+
remove : function ( a , b , d , e ) { e || b . $table . off ( ( c . events + " updateComplete.tsmath " + d . math _event ) . replace ( /\s+/g , " " ) ) . find ( "[data-" + d . math _data + "]" ) . empty ( ) } } ) } ( jQuery ) ;