@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.
- package/dist/rabex-ui.cjs.development.js +689 -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 +689 -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,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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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:
|
|
507
|
+
threshold: '1000000000000'
|
|
398
508
|
}, {
|
|
399
509
|
suffix: 'B',
|
|
400
|
-
threshold:
|
|
510
|
+
threshold: '1000000000'
|
|
401
511
|
}, {
|
|
402
512
|
suffix: 'M',
|
|
403
|
-
threshold:
|
|
513
|
+
threshold: '1000000'
|
|
404
514
|
}, {
|
|
405
515
|
suffix: 'K',
|
|
406
|
-
threshold:
|
|
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
|
-
|
|
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:
|
|
416
|
-
roundUp:
|
|
530
|
+
roundDown: enhancedRoundDown,
|
|
531
|
+
roundUp: enhancedRoundUp
|
|
417
532
|
};
|
|
418
533
|
if (found) {
|
|
419
|
-
|
|
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
|
-
|
|
539
|
+
// Return original number if no suffix applies
|
|
540
|
+
return numStr;
|
|
423
541
|
}
|
|
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
|
-
};
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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) {
|