/** * Number Formatter Utility * Formats numbers with comma separators for better readability */ // Format number with comma separators (e.g., 1234567 -> 1,234,567) function formatNumber(num) { if (!num) return ''; return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } // Remove comma separators from formatted number function unformatNumber(str) { if (!str) return ''; return str.replace(/,/g, ''); } // Extract only digits from any string function extractDigits(str) { if (!str) return ''; return str.replace(/\D/g, ''); } // Initialize number formatting for specified input selectors function initNumberFormatting(selectors) { if (typeof $ === 'undefined') { console.warn('jQuery not found. Number formatting requires jQuery.'); return; } $(document).ready(function() { selectors.forEach(function(selector) { // Store cursor position to maintain it after formatting function setCursorPosition(input, pos) { if (input.setSelectionRange) { input.setSelectionRange(pos, pos); } } $(selector).on('input', function(e) { let input = $(this); let inputElement = this; let value = input.val(); let cursorPos = inputElement.selectionStart; // Extract only digits let digitsOnly = extractDigits(value); // Store raw value input.attr('data-raw-value', digitsOnly); // Format and set the value let formattedValue = formatNumber(digitsOnly); input.val(formattedValue); // Adjust cursor position let oldLength = value.length; let newLength = formattedValue.length; let newCursorPos = cursorPos + (newLength - oldLength); // Make sure cursor position is valid if (newCursorPos < 0) newCursorPos = 0; if (newCursorPos > newLength) newCursorPos = newLength; // Set cursor position after a short delay setTimeout(function() { setCursorPosition(inputElement, newCursorPos); }, 1); }); // Handle paste events $(selector).on('paste', function(e) { let input = $(this); setTimeout(function() { let value = input.val(); let digitsOnly = extractDigits(value); input.attr('data-raw-value', digitsOnly); input.val(formatNumber(digitsOnly)); }, 1); }); }); // Before form submission, replace formatted values with raw values $('form').on('submit', function() { selectors.forEach(function(selector) { let input = $(selector); let rawValue = input.attr('data-raw-value'); if (rawValue) { input.val(rawValue); } }); }); }); } // Helper function to get raw value from formatted input function getRawValue(input) { return $(input).attr('data-raw-value') || unformatNumber($(input).val()); } // Helper function to set raw value before AJAX submission function setRawValuesForSubmission(selectors) { selectors.forEach(function(selector) { let input = $(selector); let rawValue = input.attr('data-raw-value'); if (rawValue) { input.val(rawValue); } }); } // Helper function to restore formatted values after AJAX submission function restoreFormattedValues(selectors) { selectors.forEach(function(selector) { let input = $(selector); let rawValue = input.attr('data-raw-value'); if (rawValue) { input.val(formatNumber(rawValue)); } }); } // Auto-initialize for common amount input selectors $(document).ready(function() { const commonSelectors = [ '#id_amount', '#id_charge_amount', 'input[name="amount"]', 'input[name="unit_price"]', 'input[name="price"]' ]; initNumberFormatting(commonSelectors); // Make helper functions globally available for AJAX forms window.formatNumber = formatNumber; window.unformatNumber = unformatNumber; window.getRawValue = getRawValue; // Avoid name collision causing recursion by aliasing helpers const __nf_setRawValuesForSubmission = setRawValuesForSubmission; const __nf_restoreFormattedValues = restoreFormattedValues; window.setRawValuesForSubmission = function() { __nf_setRawValuesForSubmission(commonSelectors); }; window.restoreFormattedValues = function() { __nf_restoreFormattedValues(commonSelectors); }; });