@rabex-kit/rabex-ui 0.2.45 → 0.2.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rabex-ui.cjs.development.js +714 -66
- package/dist/rabex-ui.cjs.development.js.map +1 -1
- package/dist/rabex-ui.cjs.production.min.js +1 -1
- package/dist/rabex-ui.cjs.production.min.js.map +1 -1
- package/dist/rabex-ui.esm.js +714 -66
- package/dist/rabex-ui.esm.js.map +1 -1
- package/dist/utils/numberUtils.d.ts +189 -17
- package/package.json +1 -1
|
@@ -381,73 +381,214 @@ function useOnScreen(ref, options) {
|
|
|
381
381
|
return isIntersecting;
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
+
// ============================================================================
|
|
385
|
+
// CONSTANTS & TYPE DEFINITIONS
|
|
386
|
+
// ============================================================================
|
|
387
|
+
/**
|
|
388
|
+
* Persian/Farsi numerals mapping to English numerals
|
|
389
|
+
* Used for localization and number format conversion
|
|
390
|
+
*/
|
|
384
391
|
var persianNumber = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
|
|
392
|
+
/**
|
|
393
|
+
* Standard English numerals
|
|
394
|
+
* Target format for all numeric operations
|
|
395
|
+
*/
|
|
385
396
|
var englishNumber = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
397
|
+
/**
|
|
398
|
+
* Valid decimal and thousand separator characters
|
|
399
|
+
* Allows both period and comma based on locale preferences
|
|
400
|
+
*/
|
|
386
401
|
var charachter = ['.', ','];
|
|
402
|
+
// ============================================================================
|
|
403
|
+
// CORE UTILITY FUNCTIONS - SCIENTIFIC NOTATION SAFE
|
|
404
|
+
// ============================================================================
|
|
405
|
+
/**
|
|
406
|
+
* Detect the number of meaningful decimal places in a number
|
|
407
|
+
* @param num - The number to analyze
|
|
408
|
+
* @returns Number of decimal places that contain meaningful data
|
|
409
|
+
*/
|
|
410
|
+
var detectPrecision = function detectPrecision(num) {
|
|
411
|
+
if (num === 0) return 0;
|
|
412
|
+
// Convert to string to analyze the original input precision
|
|
413
|
+
var str = num.toString();
|
|
414
|
+
// Handle scientific notation
|
|
415
|
+
if (str.includes('e')) {
|
|
416
|
+
var _str$split = str.split('e'),
|
|
417
|
+
base = _str$split[0],
|
|
418
|
+
exp = _str$split[1];
|
|
419
|
+
var exponent = parseInt(exp);
|
|
420
|
+
var baseDecimals = base.includes('.') ? base.split('.')[1].length : 0;
|
|
421
|
+
if (exponent < 0) {
|
|
422
|
+
return Math.abs(exponent) + baseDecimals;
|
|
423
|
+
} else {
|
|
424
|
+
return Math.max(0, baseDecimals - exponent);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Handle regular decimal notation
|
|
428
|
+
if (str.includes('.')) {
|
|
429
|
+
return str.split('.')[1].length;
|
|
430
|
+
}
|
|
431
|
+
return 0;
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* CONVERT SCIENTIFIC NOTATION TO DECIMAL STRING
|
|
435
|
+
*
|
|
436
|
+
* Purpose: Prevents scientific notation (1e-8) by converting to decimal format (0.00000001)
|
|
437
|
+
*
|
|
438
|
+
* @param num - Input number in any format (number, string, scientific notation)
|
|
439
|
+
* @returns Decimal string representation or undefined if invalid
|
|
440
|
+
*
|
|
441
|
+
* Key Features:
|
|
442
|
+
* - Handles very large numbers using BigInt
|
|
443
|
+
* - Handles very small numbers with proper decimal places
|
|
444
|
+
* - Returns undefined for invalid inputs (NaN, null, undefined)
|
|
445
|
+
* - Uses toFixed(20) to ensure adequate precision
|
|
446
|
+
* - Removes trailing zeros for clean output
|
|
447
|
+
*
|
|
448
|
+
* Examples:
|
|
449
|
+
* convertScientific(1e-8) → "0.00000001"
|
|
450
|
+
* convertScientific(1e8) → "100000000"
|
|
451
|
+
* convertScientific("abc") → undefined
|
|
452
|
+
*/
|
|
453
|
+
var convertScientific = function convertScientific(num) {
|
|
454
|
+
if (num === null || num === undefined || num === '') {
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
var numValue = Number(num);
|
|
458
|
+
if (isNaN(numValue) || !isFinite(numValue)) {
|
|
459
|
+
return undefined;
|
|
460
|
+
}
|
|
461
|
+
if (numValue === 0) return '0';
|
|
462
|
+
// Handle very large integers
|
|
463
|
+
if (Math.abs(numValue) >= 1e15 && Number.isInteger(numValue)) {
|
|
464
|
+
return BigInt(Math.round(numValue)).toString();
|
|
465
|
+
}
|
|
466
|
+
// Handle very small numbers
|
|
467
|
+
if (Math.abs(numValue) < 1e-15) {
|
|
468
|
+
return '0';
|
|
469
|
+
}
|
|
470
|
+
// SOLUTION 1: Intelligent precision detection
|
|
471
|
+
var detectedPrecision = detectPrecision(numValue);
|
|
472
|
+
var safePrecision = Math.min(detectedPrecision + 2, 15); // Add buffer but cap at 15
|
|
473
|
+
var result = numValue.toFixed(safePrecision).replace(/\.?0+$/, '');
|
|
474
|
+
return result;
|
|
475
|
+
};
|
|
476
|
+
/**
|
|
477
|
+
* SAFE NUMBER CONVERSION
|
|
478
|
+
*
|
|
479
|
+
* Purpose: Wrapper around convertScientific that always returns a valid string
|
|
480
|
+
*
|
|
481
|
+
* @param num - Input number in any format
|
|
482
|
+
* @returns Decimal string representation (defaults to '0' if conversion fails)
|
|
483
|
+
*
|
|
484
|
+
* This is the primary function used throughout the library to ensure
|
|
485
|
+
* all number inputs are converted to safe decimal strings before processing
|
|
486
|
+
*/
|
|
487
|
+
var safeNumber = function safeNumber(num) {
|
|
488
|
+
return convertScientific(num) || '0';
|
|
489
|
+
};
|
|
490
|
+
// ============================================================================
|
|
491
|
+
// FORMATTING & DISPLAY FUNCTIONS
|
|
492
|
+
// ============================================================================
|
|
493
|
+
/**
|
|
494
|
+
* NUMBER SUFFIX FORMATTER (K, M, B, T)
|
|
495
|
+
*
|
|
496
|
+
* Purpose: Converts large numbers to human-readable format with suffixes
|
|
497
|
+
*
|
|
498
|
+
* @param num - Input number to format
|
|
499
|
+
* @param options - Formatting options (precision, rounding method, allowed suffixes)
|
|
500
|
+
* @returns Formatted string with appropriate suffix
|
|
501
|
+
*
|
|
502
|
+
* Key Features:
|
|
503
|
+
* - Uses bigDecimal for all calculations to avoid scientific notation
|
|
504
|
+
* - Supports custom precision and rounding methods
|
|
505
|
+
* - Configurable suffix types (K=thousands, M=millions, B=billions, T=trillions)
|
|
506
|
+
* - Falls back to original number if no suffix applies
|
|
507
|
+
*
|
|
508
|
+
* Examples:
|
|
509
|
+
* suffix(1000, {precision: 1}) → "1K"
|
|
510
|
+
* suffix(1500000, {precision: 2, round: 'roundUp'}) → "1.5M"
|
|
511
|
+
* suffix(2.5e9) → "2.5B"
|
|
512
|
+
*
|
|
513
|
+
* Scientific Notation Prevention:
|
|
514
|
+
* - Uses string-based thresholds instead of numeric literals
|
|
515
|
+
* - BigDecimal comparison instead of JavaScript's Math.abs()
|
|
516
|
+
* - BigDecimal division instead of standard division operator
|
|
517
|
+
*/
|
|
387
518
|
function suffix(num, options) {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
519
|
+
if (options === void 0) {
|
|
520
|
+
options = {};
|
|
521
|
+
}
|
|
522
|
+
var _options = options,
|
|
523
|
+
_options$precision = _options.precision,
|
|
524
|
+
precision = _options$precision === void 0 ? 3 : _options$precision,
|
|
525
|
+
_options$round = _options.round,
|
|
526
|
+
round = _options$round === void 0 ? 'roundDown' : _options$round,
|
|
527
|
+
_options$suffix = _options.suffix,
|
|
528
|
+
suffix = _options$suffix === void 0 ? ['B', 'T'] : _options$suffix;
|
|
529
|
+
// Define thresholds as strings to avoid floating point precision issues
|
|
395
530
|
var map = [{
|
|
396
531
|
suffix: 'T',
|
|
397
|
-
threshold:
|
|
532
|
+
threshold: '1000000000000'
|
|
398
533
|
}, {
|
|
399
534
|
suffix: 'B',
|
|
400
|
-
threshold:
|
|
535
|
+
threshold: '1000000000'
|
|
401
536
|
}, {
|
|
402
537
|
suffix: 'M',
|
|
403
|
-
threshold:
|
|
538
|
+
threshold: '1000000'
|
|
404
539
|
}, {
|
|
405
540
|
suffix: 'K',
|
|
406
|
-
threshold:
|
|
541
|
+
threshold: '1000'
|
|
407
542
|
}, {
|
|
408
543
|
suffix: '$',
|
|
409
|
-
threshold: 1
|
|
544
|
+
threshold: '1'
|
|
410
545
|
}];
|
|
546
|
+
// Convert input to safe decimal string
|
|
547
|
+
var numStr = safeNumber(num);
|
|
548
|
+
// Find appropriate suffix using bigDecimal comparison
|
|
411
549
|
var found = map.find(function (x) {
|
|
412
|
-
|
|
550
|
+
var comparison = bigDecimal.compareTo(bigDecimal.abs(numStr), x.threshold);
|
|
551
|
+
return comparison >= 0 && _includes([].concat(suffix, ['$']), x.suffix);
|
|
413
552
|
});
|
|
553
|
+
// Reference to enhanced rounding functions
|
|
414
554
|
var func = {
|
|
415
|
-
roundDown:
|
|
416
|
-
roundUp:
|
|
555
|
+
roundDown: enhancedRoundDown,
|
|
556
|
+
roundUp: enhancedRoundUp
|
|
417
557
|
};
|
|
418
558
|
if (found) {
|
|
419
|
-
|
|
559
|
+
// Use bigDecimal division to maintain precision
|
|
560
|
+
var divided = bigDecimal.divide(numStr, found.threshold, precision + 2);
|
|
561
|
+
var formatted = func[round](parseFloat(divided), precision) + (found.suffix === '$' ? '' : found.suffix);
|
|
420
562
|
return formatted;
|
|
421
563
|
}
|
|
422
|
-
|
|
564
|
+
// Return original number if no suffix applies
|
|
565
|
+
return numStr;
|
|
423
566
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
return false;
|
|
450
|
-
};
|
|
567
|
+
/**
|
|
568
|
+
* THOUSAND SEPARATOR FORMATTER
|
|
569
|
+
*
|
|
570
|
+
* Purpose: Adds thousand separators to numbers for improved readability
|
|
571
|
+
*
|
|
572
|
+
* @param num - Input number to format
|
|
573
|
+
* @param separator - Character to use as separator (default: comma)
|
|
574
|
+
* @param separateBy - Number of digits between separators (default: 3)
|
|
575
|
+
* @returns Formatted string with separators
|
|
576
|
+
*
|
|
577
|
+
* Key Features:
|
|
578
|
+
* - Preserves decimal places
|
|
579
|
+
* - Configurable separator character and grouping
|
|
580
|
+
* - Handles both number and string inputs
|
|
581
|
+
* - Uses safeNumber conversion to avoid scientific notation
|
|
582
|
+
*
|
|
583
|
+
* Examples:
|
|
584
|
+
* delimiter(1000) → "1,000"
|
|
585
|
+
* delimiter(1234567.89) → "1,234,567.89"
|
|
586
|
+
* delimiter(1000, '.', 3) → "1.000"
|
|
587
|
+
*
|
|
588
|
+
* Scientific Notation Prevention:
|
|
589
|
+
* - Uses safeNumber() instead of toString() for number inputs
|
|
590
|
+
* - Ensures consistent decimal format before processing
|
|
591
|
+
*/
|
|
451
592
|
var _delimiter = function delimiter(num, separator, separateBy) {
|
|
452
593
|
if (separator === void 0) {
|
|
453
594
|
separator = ',';
|
|
@@ -455,75 +596,582 @@ var _delimiter = function delimiter(num, separator, separateBy) {
|
|
|
455
596
|
if (separateBy === void 0) {
|
|
456
597
|
separateBy = 3;
|
|
457
598
|
}
|
|
458
|
-
|
|
599
|
+
// Convert number inputs to safe decimal string, keep strings as-is
|
|
600
|
+
var numbers = typeof num === 'number' ? safeNumber(num) : num;
|
|
459
601
|
if (numbers) {
|
|
602
|
+
// Split into integer and decimal parts
|
|
460
603
|
var parts = numbers.split('.');
|
|
604
|
+
// Create regex pattern for inserting separators
|
|
461
605
|
var regex = new RegExp("(\\d)(?=(\\d{" + separateBy + "})+(?!\\d))", 'g');
|
|
606
|
+
// Apply separators to integer part, removing any existing separators first
|
|
462
607
|
parts[0] = _replace(parts[0].split(',').join(''), regex, "$1" + separator);
|
|
608
|
+
// Rejoin integer and decimal parts
|
|
463
609
|
return parts.join('.');
|
|
464
610
|
}
|
|
465
611
|
return num;
|
|
466
612
|
};
|
|
613
|
+
/**
|
|
614
|
+
* REMOVE THOUSAND SEPARATORS
|
|
615
|
+
*
|
|
616
|
+
* Purpose: Removes thousand separators and returns clean decimal string
|
|
617
|
+
*
|
|
618
|
+
* @param num - Input string with separators
|
|
619
|
+
* @param separator - Separator character to remove (default: comma)
|
|
620
|
+
* @returns Clean decimal string without separators
|
|
621
|
+
*
|
|
622
|
+
* Key Features:
|
|
623
|
+
* - Returns string instead of number to prevent scientific notation
|
|
624
|
+
* - Uses safeNumber conversion for validation
|
|
625
|
+
* - Preserves original precision
|
|
626
|
+
*
|
|
627
|
+
* Examples:
|
|
628
|
+
* removeDelimiter("1,234,567") → "1234567"
|
|
629
|
+
* removeDelimiter("1.234.567", ".") → "1234567"
|
|
630
|
+
*
|
|
631
|
+
* Scientific Notation Prevention:
|
|
632
|
+
* - Returns string type instead of number
|
|
633
|
+
* - Uses safeNumber() for final validation
|
|
634
|
+
*/
|
|
467
635
|
var _removeDelimiter = function removeDelimiter(num, separator) {
|
|
468
636
|
if (separator === void 0) {
|
|
469
637
|
separator = ',';
|
|
470
638
|
}
|
|
639
|
+
// Remove all instances of the separator character
|
|
471
640
|
var cleanedNumber = num.split(separator).join('');
|
|
472
|
-
|
|
641
|
+
// Return as safe decimal string instead of number to avoid scientific notation
|
|
642
|
+
return safeNumber(cleanedNumber);
|
|
473
643
|
};
|
|
644
|
+
// ============================================================================
|
|
645
|
+
// MATHEMATICAL OPERATIONS - HIGH PRECISION
|
|
646
|
+
// ============================================================================
|
|
647
|
+
/**
|
|
648
|
+
* SAFE DIVISION WITH PRECISION
|
|
649
|
+
*
|
|
650
|
+
* Purpose: Performs division using bigDecimal to maintain precision
|
|
651
|
+
*
|
|
652
|
+
* @param num1 - Dividend (number being divided)
|
|
653
|
+
* @param num2 - Divisor (number dividing by)
|
|
654
|
+
* @param precision - Number of decimal places in result
|
|
655
|
+
* @returns Division result as decimal string
|
|
656
|
+
*
|
|
657
|
+
* Key Features:
|
|
658
|
+
* - Zero division protection with console warnings
|
|
659
|
+
* - Direct bigDecimal operations (no Number conversion)
|
|
660
|
+
* - Configurable precision
|
|
661
|
+
* - Returns '0' for invalid operations
|
|
662
|
+
*
|
|
663
|
+
* Examples:
|
|
664
|
+
* divide("10", "3", 4) → "3.3333"
|
|
665
|
+
* divide(1e-8, 2, 10) → "0.000000005"
|
|
666
|
+
*
|
|
667
|
+
* Scientific Notation Prevention:
|
|
668
|
+
* - Uses safeNumber() conversion before bigDecimal operations
|
|
669
|
+
* - No intermediate Number() conversions
|
|
670
|
+
* - BigDecimal maintains precision throughout calculation
|
|
671
|
+
*/
|
|
672
|
+
var _divide = function divide(num1, num2, precision) {
|
|
673
|
+
if (precision === void 0) {
|
|
674
|
+
precision = 10;
|
|
675
|
+
}
|
|
676
|
+
// Convert inputs to safe decimal strings
|
|
677
|
+
var safeNum1 = safeNumber(num1);
|
|
678
|
+
var safeNum2 = safeNumber(num2);
|
|
679
|
+
// Check for division by zero in first operand
|
|
680
|
+
if (safeNum1 === '0') {
|
|
681
|
+
console.log('can not divide by zero! - (arguments[0])');
|
|
682
|
+
return '0';
|
|
683
|
+
}
|
|
684
|
+
// Check for division by zero in second operand
|
|
685
|
+
if (safeNum2 === '0') {
|
|
686
|
+
console.log('can not divide by zero! - (arguments[1])');
|
|
687
|
+
return '0';
|
|
688
|
+
}
|
|
689
|
+
// Perform division using bigDecimal for precision
|
|
690
|
+
return bigDecimal.divide(safeNum1, safeNum2, precision);
|
|
691
|
+
};
|
|
692
|
+
// ============================================================================
|
|
693
|
+
// ROUNDING FUNCTIONS - SCIENTIFIC NOTATION SAFE
|
|
694
|
+
// ============================================================================
|
|
695
|
+
/**
|
|
696
|
+
* ENHANCED ROUND UP FUNCTION
|
|
697
|
+
*
|
|
698
|
+
* Purpose: Rounds number up to specified decimal places using bigDecimal
|
|
699
|
+
*
|
|
700
|
+
* @param val - Number to round up
|
|
701
|
+
* @param dec - Number of decimal places
|
|
702
|
+
* @returns Rounded up value as formatted string
|
|
703
|
+
*
|
|
704
|
+
* Key Features:
|
|
705
|
+
* - Uses bigDecimal for all intermediate calculations
|
|
706
|
+
* - Handles zero decimal places (integer rounding)
|
|
707
|
+
* - Creates multipliers as strings to avoid precision loss
|
|
708
|
+
* - Formats output to remove unnecessary trailing zeros
|
|
709
|
+
*
|
|
710
|
+
* Algorithm:
|
|
711
|
+
* 1. Convert input to safe decimal string
|
|
712
|
+
* 2. For integer rounding, use bigDecimal.ceil directly
|
|
713
|
+
* 3. For decimal rounding, multiply by 10^dec, ceil, then divide back
|
|
714
|
+
* 4. Format result with proper decimal places
|
|
715
|
+
*
|
|
716
|
+
* Examples:
|
|
717
|
+
* enhancedRoundUp(3.14159, 2) → "3.15"
|
|
718
|
+
* enhancedRoundUp(1.1, 0) → "2"
|
|
719
|
+
* enhancedRoundUp(1e-8, 8) → "0.00000001"
|
|
720
|
+
*
|
|
721
|
+
* Scientific Notation Prevention:
|
|
722
|
+
* - No Number() conversions in calculations
|
|
723
|
+
* - String-based multiplier creation
|
|
724
|
+
* - BigDecimal operations maintain precision
|
|
725
|
+
*/
|
|
726
|
+
var enhancedRoundUp = function enhancedRoundUp(val, dec) {
|
|
727
|
+
// Convert input to safe decimal string
|
|
728
|
+
var valStr = safeNumber(val);
|
|
729
|
+
// Handle integer rounding (no decimal places)
|
|
730
|
+
if (dec === 0) {
|
|
731
|
+
return bigDecimal.ceil(valStr).toString();
|
|
732
|
+
}
|
|
733
|
+
// Create multiplier as string: "1000" for dec=3, "100" for dec=2, etc.
|
|
734
|
+
var multiplier = '1' + '0'.repeat(dec);
|
|
735
|
+
// Multiply by power of 10 to shift decimal places
|
|
736
|
+
var multiplied = bigDecimal.multiply(valStr, multiplier);
|
|
737
|
+
// Apply ceiling function to get round-up behavior
|
|
738
|
+
var ceiled = bigDecimal.ceil(multiplied);
|
|
739
|
+
// Divide back to restore original decimal places
|
|
740
|
+
var result = bigDecimal.divide(ceiled, multiplier, dec);
|
|
741
|
+
// Format with fixed decimal places and remove trailing zeros
|
|
742
|
+
var formatted = parseFloat(result).toFixed(dec);
|
|
743
|
+
return formatted.replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3');
|
|
744
|
+
};
|
|
745
|
+
/**
|
|
746
|
+
* ENHANCED ROUND DOWN FUNCTION
|
|
747
|
+
*
|
|
748
|
+
* Purpose: Rounds number down to specified decimal places using bigDecimal
|
|
749
|
+
*
|
|
750
|
+
* @param val - Number to round down
|
|
751
|
+
* @param dec - Number of decimal places
|
|
752
|
+
* @returns Rounded down value as formatted string
|
|
753
|
+
*
|
|
754
|
+
* Key Features:
|
|
755
|
+
* - Identical to enhancedRoundUp but uses floor instead of ceil
|
|
756
|
+
* - Same precision-safe algorithm and string-based operations
|
|
757
|
+
*
|
|
758
|
+
* Algorithm:
|
|
759
|
+
* 1. Convert input to safe decimal string
|
|
760
|
+
* 2. For integer rounding, use bigDecimal.floor directly
|
|
761
|
+
* 3. For decimal rounding, multiply by 10^dec, floor, then divide back
|
|
762
|
+
* 4. Format result with proper decimal places
|
|
763
|
+
*
|
|
764
|
+
* Examples:
|
|
765
|
+
* enhancedRoundDown(3.14159, 2) → "3.14"
|
|
766
|
+
* enhancedRoundDown(1.9, 0) → "1"
|
|
767
|
+
* enhancedRoundDown(1e-8, 8) → "0.00000001"
|
|
768
|
+
*/
|
|
769
|
+
var enhancedRoundDown = function enhancedRoundDown(val, dec) {
|
|
770
|
+
// Convert input to safe decimal string
|
|
771
|
+
var valStr = safeNumber(val);
|
|
772
|
+
// Handle integer rounding (no decimal places)
|
|
773
|
+
if (dec === 0) {
|
|
774
|
+
return bigDecimal.floor(valStr).toString();
|
|
775
|
+
}
|
|
776
|
+
// Create multiplier as string: "1000" for dec=3, "100" for dec=2, etc.
|
|
777
|
+
var multiplier = '1' + '0'.repeat(dec);
|
|
778
|
+
// Multiply by power of 10 to shift decimal places
|
|
779
|
+
var multiplied = bigDecimal.multiply(valStr, multiplier);
|
|
780
|
+
// Apply floor function to get round-down behavior
|
|
781
|
+
var floored = bigDecimal.floor(multiplied);
|
|
782
|
+
// Divide back to restore original decimal places
|
|
783
|
+
var result = bigDecimal.divide(floored, multiplier, dec);
|
|
784
|
+
// Format with fixed decimal places and remove trailing zeros
|
|
785
|
+
var formatted = parseFloat(result).toFixed(dec);
|
|
786
|
+
return formatted.replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3');
|
|
787
|
+
};
|
|
788
|
+
/**
|
|
789
|
+
* BACKWARD COMPATIBLE ROUND UP
|
|
790
|
+
*
|
|
791
|
+
* Purpose: Wrapper function maintaining original API while using enhanced implementation
|
|
792
|
+
*/
|
|
474
793
|
var _roundUp = function roundUp(val, dec) {
|
|
475
|
-
|
|
476
|
-
var result = decimal === 0 ? Math.ceil(val) : Math.ceil(+bigDecimal.multiply(val, decimal)) / decimal;
|
|
477
|
-
return result ? result.toFixed(dec).replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3') : '0';
|
|
794
|
+
return enhancedRoundUp(val, dec);
|
|
478
795
|
};
|
|
796
|
+
/**
|
|
797
|
+
* BACKWARD COMPATIBLE ROUND DOWN
|
|
798
|
+
*
|
|
799
|
+
* Purpose: Wrapper function maintaining original API while using enhanced implementation
|
|
800
|
+
*/
|
|
479
801
|
var _roundDown = function roundDown(val, dec) {
|
|
480
|
-
|
|
481
|
-
var result = decimal === 0 ? Math.floor(val) : Math.floor(+bigDecimal.multiply(val, decimal)) / decimal;
|
|
482
|
-
return result ? result.toFixed(dec).replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3') : '0';
|
|
802
|
+
return enhancedRoundDown(val, dec);
|
|
483
803
|
};
|
|
804
|
+
// ============================================================================
|
|
805
|
+
// VALIDATION & CONVERSION FUNCTIONS
|
|
806
|
+
// ============================================================================
|
|
807
|
+
/**
|
|
808
|
+
* PERSIAN TO ENGLISH NUMERAL CONVERTER
|
|
809
|
+
*
|
|
810
|
+
* Purpose: Converts Persian/Farsi numerals to English numerals
|
|
811
|
+
*
|
|
812
|
+
* @param num - Input string containing Persian numerals
|
|
813
|
+
* @returns String with English numerals
|
|
814
|
+
*
|
|
815
|
+
* Key Features:
|
|
816
|
+
* - Handles all Persian numeral characters (۰-۹)
|
|
817
|
+
* - Converts Persian decimal separator (٫) to period (.)
|
|
818
|
+
* - Uses regex replacement for efficient conversion
|
|
819
|
+
* - Pure string manipulation, no scientific notation risk
|
|
820
|
+
*
|
|
821
|
+
* Examples:
|
|
822
|
+
* toEn("۱۲۳۴") → "1234"
|
|
823
|
+
* toEn("۱۲٫۳۴") → "12.34"
|
|
824
|
+
*
|
|
825
|
+
* Algorithm:
|
|
826
|
+
* 1. Create mapping arrays for Persian to English characters
|
|
827
|
+
* 2. Iterate through each character mapping
|
|
828
|
+
* 3. Use regex to replace all instances globally
|
|
829
|
+
* 4. Return converted string
|
|
830
|
+
*/
|
|
831
|
+
var _toEn = function toEn(num) {
|
|
832
|
+
// Characters to find (Persian numerals + Persian decimal separator)
|
|
833
|
+
var find = [].concat(persianNumber, ['٫']);
|
|
834
|
+
// Replacement characters (English numerals + period)
|
|
835
|
+
var replace = [].concat(englishNumber, ['.']);
|
|
836
|
+
var replaceString = num;
|
|
837
|
+
var regex;
|
|
838
|
+
// Replace each Persian character with its English equivalent
|
|
839
|
+
for (var i = 0; i < find.length; i++) {
|
|
840
|
+
regex = new RegExp(find[i], 'g'); // Global replacement
|
|
841
|
+
replaceString = replaceString.replace(regex, replace[i]);
|
|
842
|
+
}
|
|
843
|
+
return replaceString;
|
|
844
|
+
};
|
|
845
|
+
/**
|
|
846
|
+
* INPUT CHARACTER VALIDATOR
|
|
847
|
+
*
|
|
848
|
+
* Purpose: Validates if input contains only allowed numeric characters
|
|
849
|
+
*
|
|
850
|
+
* @param num - Input to validate (number or string)
|
|
851
|
+
* @returns Boolean indicating if input is valid
|
|
852
|
+
*
|
|
853
|
+
* Key Features:
|
|
854
|
+
* - Allows Persian numerals, English numerals, periods, and commas
|
|
855
|
+
* - Handles both number and string inputs
|
|
856
|
+
* - Checks only the last character for incremental validation
|
|
857
|
+
* - Returns true for empty strings (allows clearing input)
|
|
858
|
+
*
|
|
859
|
+
* Use Cases:
|
|
860
|
+
* - Real-time input validation in forms
|
|
861
|
+
* - Preventing invalid character entry
|
|
862
|
+
* - Supporting multiple numeral systems
|
|
863
|
+
*
|
|
864
|
+
* Examples:
|
|
865
|
+
* isValid("123") → true
|
|
866
|
+
* isValid("۱۲۳") → true
|
|
867
|
+
* isValid("12.34") → true
|
|
868
|
+
* isValid("12abc") → false
|
|
869
|
+
*/
|
|
870
|
+
var _isValid = function isValid(num) {
|
|
871
|
+
// Convert number to string if needed
|
|
872
|
+
var numbers = typeof num === 'number' ? num.toString() : num;
|
|
873
|
+
// Allow empty input (user clearing the field)
|
|
874
|
+
if (numbers.length === 0) return true;
|
|
875
|
+
// Define all allowed characters
|
|
876
|
+
var allowCharachter = [].concat(persianNumber, englishNumber, charachter);
|
|
877
|
+
// Check if the last character is allowed (for incremental validation)
|
|
878
|
+
if (_includes(allowCharachter, numbers.slice(-1))) {
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
881
|
+
return false;
|
|
882
|
+
};
|
|
883
|
+
/**
|
|
884
|
+
* DECIMAL PLACES VALIDATOR
|
|
885
|
+
*
|
|
886
|
+
* Purpose: Validates if decimal places don't exceed specified limit
|
|
887
|
+
*
|
|
888
|
+
* @param val - Input string to validate
|
|
889
|
+
* @param dec - Maximum allowed decimal places
|
|
890
|
+
* @returns Boolean indicating if decimal places are within limit
|
|
891
|
+
*
|
|
892
|
+
* Key Features:
|
|
893
|
+
* - Handles strings without decimal points (always valid)
|
|
894
|
+
* - Counts decimal places after the decimal point
|
|
895
|
+
* - Used for form validation and precision control
|
|
896
|
+
*
|
|
897
|
+
* Examples:
|
|
898
|
+
* isDecimalValid("12.34", 2) → true
|
|
899
|
+
* isDecimalValid("12.345", 2) → false
|
|
900
|
+
* isDecimalValid("12", 2) → true
|
|
901
|
+
*
|
|
902
|
+
* Algorithm:
|
|
903
|
+
* 1. Convert input to string
|
|
904
|
+
* 2. Check if decimal point exists
|
|
905
|
+
* 3. If exists, count characters after decimal point
|
|
906
|
+
* 4. Compare against maximum allowed
|
|
907
|
+
*/
|
|
484
908
|
var _isDecimalValid = function isDecimalValid(val, dec) {
|
|
485
909
|
var stringVal = val.toString();
|
|
486
|
-
|
|
910
|
+
// If no decimal point, any number of allowed decimals is valid
|
|
911
|
+
return stringVal.indexOf('.') >= 0 ? !(stringVal.split('.')[1].length > dec) // Check decimal places
|
|
912
|
+
: true; // No decimal point = valid
|
|
913
|
+
};
|
|
914
|
+
// ============================================================================
|
|
915
|
+
// ENHANCED MATHEMATICAL OPERATIONS SUITE
|
|
916
|
+
// ============================================================================
|
|
917
|
+
/**
|
|
918
|
+
* SAFE MATHEMATICAL OPERATIONS OBJECT
|
|
919
|
+
*
|
|
920
|
+
* Purpose: Provides a complete suite of mathematical operations using bigDecimal
|
|
921
|
+
*
|
|
922
|
+
* Key Features:
|
|
923
|
+
* - All operations use safeNumber() conversion
|
|
924
|
+
* - Returns string results to prevent scientific notation
|
|
925
|
+
* - Consistent API across all operations
|
|
926
|
+
* - High precision calculations
|
|
927
|
+
*
|
|
928
|
+
* Available Operations:
|
|
929
|
+
* - add: Addition with precision
|
|
930
|
+
* - subtract: Subtraction with precision
|
|
931
|
+
* - multiply: Multiplication with precision
|
|
932
|
+
* - divide: Division with configurable precision
|
|
933
|
+
*
|
|
934
|
+
* Usage:
|
|
935
|
+
* safeMath.add(1e-8, 2e-8) → "0.00000003"
|
|
936
|
+
* safeMath.multiply("1.5", "2.3") → "3.45"
|
|
937
|
+
*/
|
|
938
|
+
var safeMath = {
|
|
939
|
+
/**
|
|
940
|
+
* SAFE ADDITION
|
|
941
|
+
* @param num1 - First addend
|
|
942
|
+
* @param num2 - Second addend
|
|
943
|
+
* @returns Sum as decimal string
|
|
944
|
+
*/
|
|
945
|
+
add: function add(num1, num2) {
|
|
946
|
+
return bigDecimal.add(safeNumber(num1), safeNumber(num2));
|
|
947
|
+
},
|
|
948
|
+
/**
|
|
949
|
+
* SAFE SUBTRACTION
|
|
950
|
+
* @param num1 - Minuend (number to subtract from)
|
|
951
|
+
* @param num2 - Subtrahend (number to subtract)
|
|
952
|
+
* @returns Difference as decimal string
|
|
953
|
+
*/
|
|
954
|
+
subtract: function subtract(num1, num2) {
|
|
955
|
+
return bigDecimal.subtract(safeNumber(num1), safeNumber(num2));
|
|
956
|
+
},
|
|
957
|
+
/**
|
|
958
|
+
* SAFE MULTIPLICATION
|
|
959
|
+
* @param num1 - First factor
|
|
960
|
+
* @param num2 - Second factor
|
|
961
|
+
* @returns Product as decimal string
|
|
962
|
+
*/
|
|
963
|
+
multiply: function multiply(num1, num2) {
|
|
964
|
+
return bigDecimal.multiply(safeNumber(num1), safeNumber(num2));
|
|
965
|
+
},
|
|
966
|
+
/**
|
|
967
|
+
* SAFE DIVISION
|
|
968
|
+
* @param num1 - Dividend
|
|
969
|
+
* @param num2 - Divisor
|
|
970
|
+
* @param precision - Decimal places in result (default: 10)
|
|
971
|
+
* @returns Quotient as decimal string
|
|
972
|
+
*/
|
|
973
|
+
divide: function divide(num1, num2, precision) {
|
|
974
|
+
if (precision === void 0) {
|
|
975
|
+
precision = 10;
|
|
976
|
+
}
|
|
977
|
+
return _divide(num1, num2, precision);
|
|
978
|
+
}
|
|
487
979
|
};
|
|
980
|
+
// ============================================================================
|
|
981
|
+
// MAIN EXPORT OBJECT - COMPLETE API
|
|
982
|
+
// ============================================================================
|
|
983
|
+
/**
|
|
984
|
+
* COMPREHENSIVE NUMBER UTILITIES EXPORT
|
|
985
|
+
*
|
|
986
|
+
* This object provides the complete API for all number operations, formatting,
|
|
987
|
+
* validation, and mathematical calculations. All functions are designed to
|
|
988
|
+
* prevent scientific notation and maintain high precision.
|
|
989
|
+
*
|
|
990
|
+
* Categories:
|
|
991
|
+
* 1. Formatting: delimiter, removeDelimiter, suffix
|
|
992
|
+
* 2. Rounding: roundUp, roundDown
|
|
993
|
+
* 3. Validation: isValid, isDecimalValid
|
|
994
|
+
* 4. Conversion: toEn, convertScientific, safeNumber
|
|
995
|
+
* 5. Mathematics: All bigDecimal operations + safeMath suite
|
|
996
|
+
* 6. Utilities: Direct access to bigDecimal library
|
|
997
|
+
*/
|
|
488
998
|
var numberUtils = {
|
|
999
|
+
// ============================================================================
|
|
1000
|
+
// FORMATTING & DISPLAY FUNCTIONS
|
|
1001
|
+
// ============================================================================
|
|
1002
|
+
/**
|
|
1003
|
+
* Add thousand separators to numbers
|
|
1004
|
+
* Usage: delimiter(1234567) → "1,234,567"
|
|
1005
|
+
*/
|
|
489
1006
|
delimiter: function delimiter(num, separator, separateBy) {
|
|
490
1007
|
return _delimiter(num, separator, separateBy);
|
|
491
1008
|
},
|
|
1009
|
+
/**
|
|
1010
|
+
* Remove thousand separators from formatted strings
|
|
1011
|
+
* Usage: removeDelimiter("1,234,567") → "1234567"
|
|
1012
|
+
*/
|
|
492
1013
|
removeDelimiter: function removeDelimiter(num, separator) {
|
|
493
1014
|
if (separator === void 0) {
|
|
494
1015
|
separator = ',';
|
|
495
1016
|
}
|
|
496
1017
|
return _removeDelimiter(num, separator);
|
|
497
1018
|
},
|
|
1019
|
+
/**
|
|
1020
|
+
* Format large numbers with K/M/B/T suffixes
|
|
1021
|
+
* Usage: suffix(1000000) → "1M"
|
|
1022
|
+
*/
|
|
1023
|
+
suffix: suffix,
|
|
1024
|
+
// ============================================================================
|
|
1025
|
+
// ROUNDING FUNCTIONS
|
|
1026
|
+
// ============================================================================
|
|
1027
|
+
/**
|
|
1028
|
+
* Round number down to specified decimal places
|
|
1029
|
+
* Usage: roundDown(3.14159, 2) → "3.14"
|
|
1030
|
+
*/
|
|
498
1031
|
roundDown: function roundDown(val, dec) {
|
|
499
1032
|
return _roundDown(val, dec);
|
|
500
1033
|
},
|
|
1034
|
+
/**
|
|
1035
|
+
* Round number up to specified decimal places
|
|
1036
|
+
* Usage: roundUp(3.14159, 2) → "3.15"
|
|
1037
|
+
*/
|
|
501
1038
|
roundUp: function roundUp(val, dec) {
|
|
502
1039
|
return _roundUp(val, dec);
|
|
503
1040
|
},
|
|
1041
|
+
// ============================================================================
|
|
1042
|
+
// VALIDATION FUNCTIONS
|
|
1043
|
+
// ============================================================================
|
|
1044
|
+
/**
|
|
1045
|
+
* Validate if decimal places are within specified limit
|
|
1046
|
+
* Usage: isDecimalValid("12.34", 2) → true
|
|
1047
|
+
*/
|
|
504
1048
|
isDecimalValid: function isDecimalValid(val, dec) {
|
|
505
1049
|
return _isDecimalValid(val, dec);
|
|
506
1050
|
},
|
|
1051
|
+
/**
|
|
1052
|
+
* Validate if input contains only valid numeric characters
|
|
1053
|
+
* Usage: isValid("123.45") → true
|
|
1054
|
+
*/
|
|
507
1055
|
isValid: function isValid(val) {
|
|
508
1056
|
return _isValid(val);
|
|
509
1057
|
},
|
|
1058
|
+
// ============================================================================
|
|
1059
|
+
// CONVERSION & UTILITY FUNCTIONS
|
|
1060
|
+
// ============================================================================
|
|
1061
|
+
/**
|
|
1062
|
+
* Convert Persian numerals to English numerals
|
|
1063
|
+
* Usage: toEn("۱۲۳") → "123"
|
|
1064
|
+
*/
|
|
510
1065
|
toEn: function toEn(val) {
|
|
511
1066
|
return _toEn(val);
|
|
512
1067
|
},
|
|
513
|
-
|
|
1068
|
+
/**
|
|
1069
|
+
* Convert scientific notation to decimal string
|
|
1070
|
+
* Usage: convertScientific(1e-8) → "0.00000001"
|
|
1071
|
+
*/
|
|
1072
|
+
convertScientific: convertScientific,
|
|
1073
|
+
/**
|
|
1074
|
+
* Safe number conversion with fallback to "0"
|
|
1075
|
+
* Usage: safeNumber(1e-8) → "0.00000001"
|
|
1076
|
+
*/
|
|
1077
|
+
safeNumber: safeNumber,
|
|
1078
|
+
// ============================================================================
|
|
1079
|
+
// ENHANCED MATHEMATICAL OPERATIONS
|
|
1080
|
+
// ============================================================================
|
|
1081
|
+
/**
|
|
1082
|
+
* Complete suite of safe mathematical operations
|
|
1083
|
+
* All operations prevent scientific notation and maintain precision
|
|
1084
|
+
*/
|
|
1085
|
+
safeMath: safeMath,
|
|
1086
|
+
/**
|
|
1087
|
+
* Direct access to bigDecimal library for advanced operations
|
|
1088
|
+
*/
|
|
514
1089
|
bigDecimal: bigDecimal,
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
1090
|
+
// ============================================================================
|
|
1091
|
+
// INDIVIDUAL MATHEMATICAL OPERATIONS (Enhanced with safeNumber)
|
|
1092
|
+
// ============================================================================
|
|
1093
|
+
/**
|
|
1094
|
+
* Modulus operation with precision
|
|
1095
|
+
* Usage: modulus(10, 3) → remainder as string
|
|
1096
|
+
*/
|
|
1097
|
+
modulus: function modulus(num1, num2) {
|
|
1098
|
+
return bigDecimal.modulus(safeNumber(num1), safeNumber(num2));
|
|
1099
|
+
},
|
|
1100
|
+
/**
|
|
1101
|
+
* Division with configurable precision
|
|
1102
|
+
* Usage: divide(10, 3, 4) → "3.3333"
|
|
1103
|
+
*/
|
|
1104
|
+
divide: _divide,
|
|
1105
|
+
/**
|
|
1106
|
+
* Multiplication with precision
|
|
1107
|
+
* Usage: multiply(1.5, 2.3) → "3.45"
|
|
1108
|
+
*/
|
|
1109
|
+
multiply: function multiply(num1, num2) {
|
|
1110
|
+
return bigDecimal.multiply(safeNumber(num1), safeNumber(num2));
|
|
1111
|
+
},
|
|
1112
|
+
/**
|
|
1113
|
+
* Subtraction with precision
|
|
1114
|
+
* Usage: subtract(10, 3.5) → "6.5"
|
|
1115
|
+
*/
|
|
1116
|
+
subtract: function subtract(num1, num2) {
|
|
1117
|
+
return bigDecimal.subtract(safeNumber(num1), safeNumber(num2));
|
|
1118
|
+
},
|
|
1119
|
+
/**
|
|
1120
|
+
* Addition with precision
|
|
1121
|
+
* Usage: add(1.1, 2.2) → "3.3"
|
|
1122
|
+
*/
|
|
1123
|
+
add: function add(num1, num2) {
|
|
1124
|
+
return bigDecimal.add(safeNumber(num1), safeNumber(num2));
|
|
1125
|
+
},
|
|
1126
|
+
/**
|
|
1127
|
+
* Number negation
|
|
1128
|
+
* Usage: negate(5) → "-5"
|
|
1129
|
+
*/
|
|
1130
|
+
negate: function negate(num) {
|
|
1131
|
+
return bigDecimal.negate(safeNumber(num));
|
|
1132
|
+
},
|
|
1133
|
+
/**
|
|
1134
|
+
* Number comparison (-1: less, 0: equal, 1: greater)
|
|
1135
|
+
* Usage: compareTo(5, 3) → 1
|
|
1136
|
+
*/
|
|
1137
|
+
compareTo: function compareTo(num1, num2) {
|
|
1138
|
+
return bigDecimal.compareTo(safeNumber(num1), safeNumber(num2));
|
|
1139
|
+
},
|
|
1140
|
+
/**
|
|
1141
|
+
* Ceiling function (round up to nearest integer)
|
|
1142
|
+
* Usage: ceil(3.14) → "4"
|
|
1143
|
+
*/
|
|
1144
|
+
ceil: function ceil(num) {
|
|
1145
|
+
return bigDecimal.ceil(safeNumber(num));
|
|
1146
|
+
},
|
|
1147
|
+
/**
|
|
1148
|
+
* Floor function (round down to nearest integer)
|
|
1149
|
+
* Usage: floor(3.14) → "3"
|
|
1150
|
+
*/
|
|
1151
|
+
floor: function floor(num) {
|
|
1152
|
+
return bigDecimal.floor(safeNumber(num));
|
|
1153
|
+
},
|
|
1154
|
+
/**
|
|
1155
|
+
* Absolute value
|
|
1156
|
+
* Usage: abs(-5) → "5"
|
|
1157
|
+
*/
|
|
1158
|
+
abs: function abs(num) {
|
|
1159
|
+
return bigDecimal.abs(safeNumber(num));
|
|
1160
|
+
},
|
|
1161
|
+
/**
|
|
1162
|
+
* Round to specified precision
|
|
1163
|
+
* Usage: round(3.14159, 2) → "3.14"
|
|
1164
|
+
*/
|
|
1165
|
+
round: function round(num, precision) {
|
|
1166
|
+
return bigDecimal.round(safeNumber(num), precision);
|
|
1167
|
+
},
|
|
1168
|
+
/**
|
|
1169
|
+
* Format number with pretty printing (thousands separators)
|
|
1170
|
+
* Usage: getPrettyValue(1234567, 2, ",") → "1,234,567.00"
|
|
1171
|
+
*/
|
|
1172
|
+
getPrettyValue: function getPrettyValue(num, precision, separator) {
|
|
1173
|
+
return bigDecimal.getPrettyValue(safeNumber(num), precision, separator);
|
|
1174
|
+
}
|
|
527
1175
|
};
|
|
528
1176
|
|
|
529
1177
|
var handleSearch = function handleSearch(list, value) {
|