UNPKG

fonteva-design-guide

Version:

## Dev, Build and Test

313 lines (278 loc) 24.3 kB
import { loadScript } from 'lightning/platformResourceLoader'; import BASE from '@salesforce/resourceUrl/PFM_Base'; const nativeMap = Array.prototype.map, nativeIsArray = Array.isArray, toString = Object.prototype.toString; let settings = { currency: { symbol: '$', // default currency symbol is '$' format: '%s%v', // controls output: %s = symbol, %v = value (can be object, see docs) decimal: '.', // decimal point separator thousand: ',', // thousands separator precision: 2, // decimal places grouping: 3 // digit grouping (not implemented yet) }, number: { precision: 0, // default precision on numbers is 0 grouping: 3, // digit grouping (not implemented yet) thousand: ',', decimal: '.' } }; /** * Extends an object with a defaults object, similar to underscore's _.defaults * * Used for abstracting parameter handling from API methods */ const defaults = function (object, defs) { var key; object = object || {}; defs = defs || {}; // Iterate over object non-prototype properties: for (key in defs) { if (defs.hasOwnProperty(key)) { // Replace values with defaults only if undefined (allow empty/zero values): if (object[key] == null) object[key] = defs[key]; } } return object; }; /** * Takes a string/array of strings, removes all formatting/cruft and returns the raw float value * Alias: `accounting.parse(string)` * * Decimal must be included in the regular expression to match floats (defaults to * accounting.settings.number.decimal), so if the number uses a non-standard decimal * separator, provide it as the second argument. * * Also matches bracketed negatives (eg. "$ (1.99)" => -1.99) * * Doesn't throw any errors (`NaN`s become 0) but this may change in future */ const unformat = function (value, decimal) { // Recursively unformat arrays: if (isArray(value)) { return map(value, function (val) { return unformat(val, decimal); }); } // Fails silently (need decent errors): value = value || 0; // Return the value as-is if it's already a number: if (typeof value === 'number') return value; // Default decimal point comes from settings, but could be set to eg. "," in opts: decimal = decimal || settings.number.decimal; // Build regex to strip out everything except digits, decimal point and minus sign: var regex = new RegExp('[^0-9-' + decimal + ']', ['g']), unformatted = parseFloat( ('' + value) .replace(/\((?=\d+)(.*)\)/, '-$1') // replace bracketed values with negatives .replace(regex, '') // strip out any cruft .replace(decimal, '.') // make sure decimal point is standard ); // This will fail silently which may cause trouble, let's wait and see: return !isNaN(unformatted) ? unformatted : 0; }; /** * Parses a format string or object and returns format obj for use in rendering * * `format` is either a string with the default (positive) format, or object * containing `pos` (required), `neg` and `zero` values (or a function returning * either a string or object) * * Either string or format.pos must contain "%v" (value) to be valid */ const checkCurrencyFormat = function (format) { var defaults = settings.currency.format; // Allow function as format parameter (should return string or object): if (typeof format === 'function') format = format(); // Format can be a string, in which case `value` ("%v") must be present: if (isString(format) && format.match('%v')) { // Create and return positive, negative and zero formats: return { pos: format, neg: format.replace('-', '').replace('%v', '-%v'), zero: format }; // If no format, or object is missing valid positive value, use defaults: } else if (!format || !format.pos || !format.pos.match('%v')) { // If defaults is a string, casts it to an object for faster checking next time: return !isString(defaults) ? defaults : (settings.currency.format = { pos: defaults, neg: defaults.replace('%v', '-%v'), zero: defaults }); } // Otherwise, assume format was fine: return format; }; /** * Tests whether supplied parameter is a string * from underscore.js */ const isString = function (obj) { return !!(obj === '' || (obj && obj.charCodeAt && obj.substr)); }; /** * Tests whether supplied parameter is an array * from underscore.js, delegates to ECMA5's native Array.isArray */ const isArray = function (obj) { return nativeIsArray ? nativeIsArray(obj) : toString.call(obj) === '[object Array]'; }; /** * Implementation of toFixed() that treats floats more like decimals * * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present * problems for accounting- and finance-related software. */ const toFixed = function (value, precision) { precision = checkPrecision(precision, settings.number.precision); var exponentialForm = Number(unformat(value) + 'e' + precision); var rounded = Math.round(exponentialForm); var finalResult = Number(rounded + 'e-' + precision).toFixed(precision); return finalResult; }; /** * Check and normalise the value of precision (must be positive integer) */ const checkPrecision = function (val, base) { val = Math.round(Math.abs(val)); return isNaN(val) ? base : val; }; /** * Tests whether supplied parameter is a true object */ const isObject = function (obj) { return obj && toString.call(obj) === '[object Object]'; }; /** * Format a number, with comma-separated thousands and custom precision/decimal places * Alias: `accounting.format()` * * Localise by overriding the precision and thousand / decimal separators * 2nd parameter `precision` can be an object matching `settings.number` */ const formatNumber = function (number, precision, thousand, decimal) { // Resursively format arrays: if (isArray(number)) { return map(number, function (val) { return formatNumber(val, precision, thousand, decimal); }); } // Clean up number: number = unformat(number); // Build options object from second param (if object) or all params, extending defaults: var opts = defaults( isObject(precision) ? precision : { precision: precision, thousand: thousand, decimal: decimal }, settings.number ), // Clean up precision usePrecision = checkPrecision(opts.precision), // Do some calc: negative = number < 0 ? '-' : '', base = parseInt(toFixed(Math.abs(number || 0), usePrecision), 10) + '', mod = base.length > 3 ? base.length % 3 : 0; // Format the number: return ( negative + (mod ? base.substr(0, mod) + opts.thousand : '') + base.substr(mod).replace(/(\d{3})(?=\d)/g, '$1' + opts.thousand) + (usePrecision ? opts.decimal + toFixed(Math.abs(number), usePrecision).split('.')[1] : '') ); }; /** * Format a number into currency * * Usage: accounting.formatMoney(number, symbol, precision, thousandsSep, decimalSep, format) * defaults: (0, "$", 2, ",", ".", "%s%v") * * Localise by overriding the symbol, precision, thousand / decimal separators and format * Second param can be an object matching `settings.currency` which is the easiest way. * * To do: tidy up the parameters */ const formatMoney = function (number, symbol, precision, thousand, decimal, format) { // Resursively format arrays: if (isArray(number)) { return map(number, function (val) { return formatMoney(val, symbol, precision, thousand, decimal, format); }); } // Clean up number: number = unformat(number); // Build options object from second param (if object) or all params, extending defaults: var opts = defaults( isObject(symbol) ? symbol : { symbol: symbol, precision: precision, thousand: thousand, decimal: decimal, format: format }, settings.currency ), // Check format (returns object with pos, neg and zero): formats = checkCurrencyFormat(opts.format), // Choose which format to use for this value: useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero; // Return with currency symbol added: return useFormat .replace('%s', opts.symbol) .replace('%v', formatNumber(Math.abs(number), checkPrecision(opts.precision), opts.thousand, opts.decimal)); }; const buildCurrencyMap = function (isocode) { const currencyJSON = '[ { "isocode" : "ALL", "symbol" : "\u004c\u0065\u006b", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "AFN", "symbol" : "\u060b", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "ARS", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "AWG", "symbol" : "\u0192", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "AUD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "AZN", "symbol" : "\u043c\u0430\u043d\u002e", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BSD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BBD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BYR", "symbol" : "\u0070\u002e", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BZD", "symbol" : "\u0042\u005a\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BMD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BOB", "symbol" : "\u0024\u0062", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BAM", "symbol" : "\u004b\u004d", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BWP", "symbol" : "\u0050", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BGN", "symbol" : "\u043b\u0432", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BRL", "symbol" : "\u0052\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "BND", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KHR", "symbol" : "\u17db", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CAD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KYD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CLP", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CNY", "symbol" : "\u00a5", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "COP", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CRC", "symbol" : "\u20a1", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "HRK", "symbol" : "\u006b\u006e", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CUP", "symbol" : "\u20b1", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CZK", "symbol" : "\u004b\u010d", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "DKK", "symbol" : "\u006b\u0072", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "DOP", "symbol" : "\u0052\u0044\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "XCD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "EGP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SVC", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "EEK", "symbol" : "\u006b\u0072", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "EUR", "symbol" : "\u20ac", "format" : "%v %s", "thousand" : ".", "decimal" : "," }, { "isocode" : "FKP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "FJD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "GHC", "symbol" : "\u00a2", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "GIP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "GTQ", "symbol" : "\u0051", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "GGP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "GYD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "HNL", "symbol" : "\u004c", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "HKD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "HUF", "symbol" : "\u0046\u0074", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "ISK", "symbol" : "\u006b\u0072", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "INR", "symbol" : "\u0930", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "IDR", "symbol" : "\u0052\u0070", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "IRR", "symbol" : "\ufdfc", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "IMP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "ILS", "symbol" : "\u20aa", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "JMD", "symbol" : "\u004a\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "JPY", "symbol" : "\u00a5", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "JEP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KZT", "symbol" : "\u043b\u0432", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KPW", "symbol" : "\u20a9", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KRW", "symbol" : "\u20a9", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KGS", "symbol" : "\u043b\u0432", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "LVL", "symbol" : "\u004c\u0073", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "LBP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "LRD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "LTL", "symbol" : "\u004c\u0074", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "MKD", "symbol" : "\u0434\u0435\u043d", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "MYR", "symbol" : "\u0052\u004d", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "MUR", "symbol" : "\u20a8", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "MXN", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "MNT", "symbol" : "\u20ae", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "MZN", "symbol" : "\u004d\u0054", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "NAD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "NPR", "symbol" : "\u20a8", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "ANG", "symbol" : "\u0192", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "NZD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "NIO", "symbol" : "\u0043\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "NGN", "symbol" : "\u20a6", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "NOK", "symbol" : "\u006b\u0072", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "OMR", "symbol" : "\ufdfc", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "PKR", "symbol" : "\u20a8", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "PAB", "symbol" : "\u0042\u002f\u002e", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "PYG", "symbol" : "\u0047\u0073", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "PEN", "symbol" : "\u0053\u002f\u002e", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "PHP", "symbol" : "\u20b1", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "PLN", "symbol" : "\u007a\u0142", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "QAR", "symbol" : "\ufdfc", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "RON", "symbol" : "\u006c\u0065\u0069", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "RUB", "symbol" : "\u0440\u0443\u0431", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SHP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SAR", "symbol" : "\ufdfc", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "RSD", "symbol" : "\u0414\u0438\u043d\u002e", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SCR", "symbol" : "\u20a8", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SGD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SBD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SOS", "symbol" : "\u0053", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "ZAR", "symbol" : "\u0052", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "KRW", "symbol" : "\u20a9", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "LKR", "symbol" : "\u20a8", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SEK", "symbol" : "\u006b\u0072", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "CHF", "symbol" : "\u0043\u0048\u0046", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SRD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "SYP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "TWD", "symbol" : "\u004e\u0054\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "THB", "symbol" : "\u0e3f", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "TTD", "symbol" : "\u0054\u0054\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "TRY", "symbol" : "TL", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "TRL", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "TVD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "UAH", "symbol" : "\u20b4", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "GBP", "symbol" : "\u00a3", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "USD", "symbol" : "\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "UYU", "symbol" : "\u0024U", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "UZS", "symbol" : "\u043b\u0432", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "VEF", "symbol" : "\u0042\u0073", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "VND", "symbol" : "\u20ab", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "YER", "symbol" : "\ufdfc", "format" : "%s%v", "thousand" : ",", "decimal" : "." }, { "isocode" : "ZWD", "symbol" : "\u005a\u0024", "format" : "%s%v", "thousand" : ",", "decimal" : "." }]'; const currencyObject = JSON.parse(currencyJSON); let currencyISOMap = new Object(); // currencySymbolMap = new Object(); //build the maps for (var cur in currencyObject) { currencyISOMap[currencyObject[cur].isocode] = currencyObject[cur]; // this.currencySymbolMap[currencyObject[cur].symbol] = currencyObject[cur]; } // this.defaultISOCode = isocode; return currencyISOMap; }; const format = function (value, isocode, isMultiCurrency) { const currencyISOMap = buildCurrencyMap(isocode); let symbol = currencyISOMap[isocode].symbol; let format = currencyISOMap[isocode].format; if (isMultiCurrency) { format = '%s %v'; symbol = currencyISOMap[isocode].isocode; } const options = { symbol: symbol, decimal: currencyISOMap[isocode].decimal, thousand: currencyISOMap[isocode].thousand, precision: '2', format: format }; if (typeof value !== 'undefined' && value !== null) { return formatMoney(parseFloat(value), options); } else { return value; } }; const formatValue = function (cmp, val, currencyISOCode, isMultiCurrencyOrg) { return new Promise(function (resolve, reject) { Promise.all([loadScript(cmp, BASE + '/js/accounting.js'), loadScript(cmp, BASE + '/js/currencytable.js')]).then( () => { resolve(CurrencyTable.format(val, currencyISOCode, isMultiCurrencyOrg)); } ); }); }; export { formatValue, format };