@@ -72,7 +72,7 @@ window.PYWRY_AGGRID_DEFAULT_COL_DEF = {
7272 sortable : true ,
7373 resizable : true ,
7474 wrapText : true ,
75- wrapHeaderText : true ,
75+ wrapHeaderText : false ,
7676 autoHeight : true ,
7777 filterParams : {
7878 buttons : [ 'apply' , 'clear' , 'reset' ] ,
@@ -82,60 +82,53 @@ window.PYWRY_AGGRID_DEFAULT_COL_DEF = {
8282} ;
8383
8484/**
85- * Format numbers intelligently:
86- * - Large integers with trailing zeros → K/M/B (75000 → "75K")
87- * - Large integers without trailing zeros → commas (75123 → "75,123")
88- * - Small decimals (< 1) → preserve full precision, no truncation
89- * - Very small numbers (many leading zeros) → scientific notation
90- * - Regular decimals → preserve full precision
85+ * Format numbers with predictable compact notation.
9186 *
92- * @param {number } value - The number to format
93- * @returns {string } Formatted number string
87+ * Rules:
88+ * - Always promote large magnitudes to the highest sensible unit (K/M/B/T).
89+ * - Avoid giant K values (e.g. 19,225,200K) by promoting to M/B/T.
90+ * - Keep small/medium numbers comma-formatted unless K is clean (divisible by 1,000).
91+ * - Preserve decimal precision for normal decimals; scientific for very tiny values.
9492 */
9593window . PYWRY_FORMAT_NUMBER = function ( value ) {
9694 if ( value == null || isNaN ( value ) ) return '' ;
9795
9896 var absValue = Math . abs ( value ) ;
99- var sign = value < 0 ? '-' : '' ;
10097
101- // Very small numbers (with many leading zeros after decimal) → scientific notation
102- // e.g., 0.00000123 → "1.23e-6"
98+ // Very small non-zero values: keep scientific notation readable
10399 if ( absValue > 0 && absValue < 0.0001 ) {
104- return value . toExponential ( ) ;
100+ return value . toExponential ( 2 ) ;
105101 }
106102
107- // Handle non -integers (decimals) - add thousand separators
103+ // Non -integers: preserve precision while adding comma separators to integer part
108104 if ( ! Number . isInteger ( value ) ) {
109- var parts = value . toString ( ) . split ( '.' ) ;
110- var integerPart = parseInt ( parts [ 0 ] ) ;
105+ var parts = String ( value ) . split ( '.' ) ;
106+ var integerPart = Number ( parts [ 0 ] || 0 ) ;
111107 var decimalPart = parts [ 1 ] || '' ;
112-
113- // Format integer part with commas
114108 var formattedInteger = integerPart . toLocaleString ( 'en-US' ) ;
115-
116- // Return with decimal part preserved
117109 return decimalPart ? formattedInteger + '.' + decimalPart : formattedInteger ;
118110 }
119111
120- // From here, we're dealing with integers only
121- // Abbreviate integers with trailing zeros consistently
122-
123- // Billions (1,000,000,000+) - must be divisible by 1B
124- if ( absValue >= 1e9 && absValue % 1e9 === 0 ) {
125- return sign + ( absValue / 1e9 ) . toFixed ( 0 ) + 'B' ;
112+ function formatCompact ( n , divisor , suffix ) {
113+ var compact = n / divisor ;
114+ var decimals = compact >= 100 ? 0 : ( compact >= 10 ? 1 : 2 ) ;
115+ var rounded = compact . toFixed ( decimals ) ;
116+ if ( rounded . indexOf ( '.' ) !== - 1 ) {
117+ rounded = rounded . replace ( / 0 + $ / , '' ) . replace ( / \. $ / , '' ) ;
118+ }
119+ return rounded + suffix ;
126120 }
127121
128- // Millions (1,000,000+) - must be divisible by 1M
129- if ( absValue >= 1e6 && absValue % 1e6 === 0 ) {
130- return sign + ( absValue / 1e6 ) . toFixed ( 0 ) + 'M' ;
131- }
122+ // Always use the highest magnitude for million+ values
123+ if ( absValue >= 1e12 ) return formatCompact ( value , 1e12 , 'T' ) ;
124+ if ( absValue >= 1e9 ) return formatCompact ( value , 1e9 , 'B' ) ;
125+ if ( absValue >= 1e6 ) return formatCompact ( value , 1e6 , 'M' ) ;
132126
133- // Thousands (1,000+) - must be divisible by 1K
127+ // For thousands, keep comma format unless it's a clean thousand (e.g., 75,000 -> 75K)
134128 if ( absValue >= 1e3 && absValue % 1e3 === 0 ) {
135- return sign + ( absValue / 1e3 ) . toFixed ( 0 ) + 'K' ;
129+ return formatCompact ( value , 1e3 , 'K' ) ;
136130 }
137131
138- // Otherwise use thousand separators for non-abbreviatable integers
139132 return value . toLocaleString ( 'en-US' ) ;
140133} ;
141134
@@ -157,6 +150,13 @@ window.PYWRY_AGGRID_PROCESS_COLUMN_DEFS = function(columnDefs) {
157150 delete processed . cellDataType ;
158151 }
159152
153+ if ( processed . headerTooltip === undefined || processed . headerTooltip === null || processed . headerTooltip === '' ) {
154+ var headerLabel = processed . headerName || processed . field || processed . colId ;
155+ if ( headerLabel !== undefined && headerLabel !== null && String ( headerLabel ) . length > 8 ) {
156+ processed . headerTooltip = String ( headerLabel ) ;
157+ }
158+ }
159+
160160 // Convert valueGetter string to function
161161 // Expression can use: params, data, node, colDef, column, api, columnApi, context
162162 if ( typeof processed . valueGetter === 'string' ) {
@@ -288,6 +288,7 @@ window.PYWRY_AGGRID_BUILD_OPTIONS = function(config, gridId) {
288288 */
289289window . PYWRY_AGGRID_BUILD_CLIENT_OPTIONS = function ( config , id , rowData , rowCount , truncatedRows ) {
290290 var LARGE_DATASET_THRESHOLD = 10000 ;
291+ var isNativeWebKit = document . documentElement . classList . contains ( 'pywry-native' ) ;
291292
292293 // Pagination logic:
293294 // - If config.pagination === true: always enable
@@ -337,6 +338,9 @@ window.PYWRY_AGGRID_BUILD_CLIENT_OPTIONS = function(config, id, rowData, rowCoun
337338 suppressMenuHide : true ,
338339 enableCellTextSelection : true ,
339340 ensureDomOrder : true ,
341+ suppressAnimationFrame : isNativeWebKit ,
342+ tooltipShowDelay : 1200 ,
343+ tooltipHideDelay : 5000 ,
340344 // Row spanning support (AG Grid v32+)
341345 enableCellSpan : config . enableCellSpan || false ,
342346
@@ -390,6 +394,16 @@ window.PYWRY_AGGRID_BUILD_CLIENT_OPTIONS = function(config, id, rowData, rowCoun
390394 ' of ' + ( rowCount + truncatedRows ) . toLocaleString ( ) + ' rows'
391395 } ) ;
392396 }
397+ } ,
398+
399+ onBodyScroll : function ( event ) {
400+ if ( ! isNativeWebKit ) return ;
401+ if ( ! event || ! event . api ) return ;
402+ window . requestAnimationFrame ( function ( ) {
403+ try {
404+ event . api . redrawRows ( ) ;
405+ } catch ( e ) { }
406+ } ) ;
393407 }
394408 } ;
395409
@@ -415,6 +429,7 @@ window.PYWRY_AGGRID_BUILD_SERVER_SIDE_OPTIONS = function(config, id, serverConfi
415429 var totalRows = serverConfig . totalRows || 0 ;
416430 var blockSize = serverConfig . blockSize || 500 ; // Rows per block for infinite scroll
417431 var currentFilteredTotal = totalRows ;
432+ var isNativeWebKit = document . documentElement . classList . contains ( 'pywry-native' ) ;
418433
419434 // Pending requests
420435 var pendingRequests = { } ;
@@ -517,6 +532,9 @@ window.PYWRY_AGGRID_BUILD_SERVER_SIDE_OPTIONS = function(config, id, serverConfi
517532 suppressMenuHide : true ,
518533 enableCellTextSelection : true ,
519534 ensureDomOrder : true ,
535+ suppressAnimationFrame : isNativeWebKit ,
536+ tooltipShowDelay : 1200 ,
537+ tooltipHideDelay : 5000 ,
520538
521539 // Row ID for selection persistence
522540 getRowId : function ( params ) {
@@ -616,6 +634,16 @@ window.PYWRY_AGGRID_BUILD_SERVER_SIDE_OPTIONS = function(config, id, serverConfi
616634 ' rows). Use filters to narrow down results.'
617635 } ) ;
618636 }
637+ } ,
638+
639+ onBodyScroll : function ( event ) {
640+ if ( ! isNativeWebKit ) return ;
641+ if ( ! event || ! event . api ) return ;
642+ window . requestAnimationFrame ( function ( ) {
643+ try {
644+ event . api . redrawRows ( ) ;
645+ } catch ( e ) { }
646+ } ) ;
619647 }
620648 } ;
621649
0 commit comments