fonteva-design-guide
Version:
## Dev, Build and Test
313 lines (278 loc) • 24.3 kB
JavaScript
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 };