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