'use strict' ; import type Chart from './Chart/Chart' ; import D from './DefaultOptions.js' ; const { defaultOptions , defaultTime } = D ; import U from './Utilities.js' ; const { getNestedProperty , isNumber , pick , pInt } = U ; /**
 * Formats a JavaScript date timestamp (milliseconds since Jan 1st 1970) into a
 * human readable date string. The format is a subset of the formats for PHP's
 * [strftime](https://www.php.net/manual/en/function.strftime.php) function.
 * Additional formats can be given in the  Highcharts . dateFormats hook.
 *
 * Since v6.0.5, all internal dates are formatted through the
 *  Highcharts . Chart instance to respect chart-level time settings.
 * The `Highcharts.dateFormat` function only reflects global time settings set
 * with `setOptions`.
 *
 * Supported format keys:
 * - `%a`: Short weekday, like 'Mon'
 * - `%A`: Long weekday, like 'Monday'
 * - `%d`: Two digit day of the month, 01 to 31
 * - `%e`: Day of the month, 1 through 31
 * - `%w`: Day of the week, 0 through 6
 * - `%b`: Short month, like 'Jan'
 * - `%B`: Long month, like 'January'
 * - `%m`: Two digit month number, 01 through 12
 * - `%y`: Two digits year, like 09 for 2009
 * - `%Y`: Four digits year, like 2009
 * - `%H`: Two digits hours in 24h format, 00 through 23
 * - `%k`: Hours in 24h format, 0 through 23
 * - `%I`: Two digits hours in 12h format, 00 through 11
 * - `%l`: Hours in 12h format, 1 through 12
 * - `%M`: Two digits minutes, 00 through 59
 * - `%p`: Upper case AM or PM
 * - `%P`: Lower case AM or PM
 * - `%S`: Two digits seconds, 00 through 59
 * - `%L`: Milliseconds (naming from Ruby)
 *
 *  function param { string } format param { number } timestamp param { boolean } capitalize return { string } function dateFormat ( format , timestamp , capitalize ? ) { return defaultTime . dateFormat ( format , timestamp , capitalize ) ; } example function param { string } str param { Record < string , * > } ctx param { Highcharts . Chart } chart return { string } function format ( str , ctx , chart ? ) { let splitter = '{' , isInside = false , segment , valueAndFormat , val , index ; const floatRegex = /f$/ ; const decRegex = /\.([0-9])/ ; const lang = defaultOptions . lang ; const time = chart && chart . time || defaultTime ; const numberFormatter = chart && chart . numberFormatter || numberFormat ; const ret = [ ] ; while ( str ) { index = str . indexOf ( splitter ) ; if ( index === - 1 ) { break ; } segment = str . slice ( 0 , index ) ; if ( isInside ) { valueAndFormat = segment . split ( ':' ) ; val = getNestedProperty ( valueAndFormat . shift ( ) || '' , ctx ) ; if ( valueAndFormat . length && typeof val === 'number' ) { segment = valueAndFormat . join ( ':' ) ; if ( floatRegex . test ( segment ) ) { const decimals = parseInt ( ( segment . match ( decRegex ) || [ '' , '-1' ] ) [ 1 ] , 10 ) ; if ( val !== null ) { val = numberFormatter ( val , decimals , lang . decimalPoint , segment . indexOf ( ',' ) > - 1 ? lang . thousandsSep : '' ) ; } } else { val = time . dateFormat ( segment , val ) ; } } ret . push ( val ) ; } else { ret . push ( segment ) ; } str = str . slice ( index + 1 ) ; isInside = ! isInside ; splitter = isInside ? '}' : '{' ; } ret . push ( str ) ; return ret . join ( '' ) ; } sample function param { number } number param { number } decimals param { string } decimalPoint param { string } thousandsSep return { string } function numberFormat ( number , decimals , decimalPoint ? , thousandsSep ? ) { number = + number || 0 ; decimals = + decimals ; let ret , fractionDigits ; const lang = defaultOptions . lang , origDec = ( number . toString ( ) . split ( '.' ) [ 1 ] || '' ) . split ( 'e' ) [ 0 ] . length , exponent = number . toString ( ) . split ( 'e' ) , firstDecimals = decimals ; if ( decimals === - 1 ) { decimals = Math . min ( origDec , 20 ) ; } else if ( ! isNumber ( decimals ) ) { decimals = 2 ; } else if ( decimals && exponent [ 1 ] && exponent [ 1 ] as any < 0 ) { fractionDigits = decimals + + exponent [ 1 ] ; if ( fractionDigits >= 0 ) { exponent [ 0 ] = ( + exponent [ 0 ] ) . toExponential ( fractionDigits ) . split ( 'e' ) [ 0 ] ; decimals = fractionDigits ; } else { exponent [ 0 ] = exponent [ 0 ] . split ( '.' ) [ 0 ] || 0 as any ; if ( decimals < 20 ) { number = ( exponent [ 0 ] as any * Math . pow ( 10 , exponent [ 1 ] as any ) ) . toFixed ( decimals ) as any ; } else { number = 0 ; } exponent [ 1 ] = 0 as any ; } } const roundedNumber = ( Math . abs ( exponent [ 1 ] ? exponent [ 0 ] as any : number ) + Math . pow ( 10 , - Math . max ( decimals , origDec ) - 1 ) ) . toFixed ( decimals ) ; const strinteger = String ( pInt ( roundedNumber ) ) ; const thousands = strinteger . length > 3 ? strinteger . length % 3 : 0 ; decimalPoint = pick ( decimalPoint , lang . decimalPoint ) ; thousandsSep = pick ( thousandsSep , lang . thousandsSep ) ; ret = number < 0 ? '-' : '' ; ret += thousands ? strinteger . substr ( 0 , thousands ) + thousandsSep : '' ; if ( + exponent [ 1 ] < 0 && ! firstDecimals ) { ret = '0' ; } else { ret += strinteger . substr ( thousands ) . replace ( /(\d{3})(?=\d)/g , '$1' + thousandsSep ) ; } if ( decimals ) { ret += decimalPoint + roundedNumber . slice ( - decimals ) ; } if ( exponent [ 1 ] && + ret !== 0 ) { ret += 'e' + exponent [ 1 ] ; } return ret ; } const FormatUtilities = { dateFormat , format , numberFormat } ; namespace FormatUtilities { export interface FormatterCallback < T > { ( this ) : string ; } } export default FormatUtilities ;