@rabex-kit/rabex-ui 0.2.45 → 0.2.46

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