@rabex-kit/rabex-ui 0.2.45 → 0.2.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rabex-ui.cjs.development.js +714 -66
- package/dist/rabex-ui.cjs.development.js.map +1 -1
- package/dist/rabex-ui.cjs.production.min.js +1 -1
- package/dist/rabex-ui.cjs.production.min.js.map +1 -1
- package/dist/rabex-ui.esm.js +714 -66
- package/dist/rabex-ui.esm.js.map +1 -1
- package/dist/utils/numberUtils.d.ts +189 -17
- package/package.json +1 -1
package/dist/rabex-ui.esm.js
CHANGED
|
@@ -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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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:
|
|
528
|
+
threshold: '1000000000000'
|
|
394
529
|
}, {
|
|
395
530
|
suffix: 'B',
|
|
396
|
-
threshold:
|
|
531
|
+
threshold: '1000000000'
|
|
397
532
|
}, {
|
|
398
533
|
suffix: 'M',
|
|
399
|
-
threshold:
|
|
534
|
+
threshold: '1000000'
|
|
400
535
|
}, {
|
|
401
536
|
suffix: 'K',
|
|
402
|
-
threshold:
|
|
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
|
-
|
|
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:
|
|
412
|
-
roundUp:
|
|
551
|
+
roundDown: enhancedRoundDown,
|
|
552
|
+
roundUp: enhancedRoundUp
|
|
413
553
|
};
|
|
414
554
|
if (found) {
|
|
415
|
-
|
|
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
|
-
|
|
560
|
+
// Return original number if no suffix applies
|
|
561
|
+
return numStr;
|
|
419
562
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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) {
|