@fleetbase/ember-accounting
Version:
Updated port of the great accounting.js library to ES6 modules that integrates seamlessly with ember-cli
90 lines (79 loc) • 3.83 kB
JavaScript
import { isArray } from '@ember/array';
import { currency } from '../settings';
import { defaults, checkPrecision, isObject, checkCurrencyFormat } from '../utils';
import formatNumber from './format-number';
import unformat from './unformat';
/**
* Format a list of numbers into an accounting column, padding with whitespace
* to line up currency symbols, thousand separators and decimals places
*
* Second parameter can be an object containing keys that match the params
*
* NB: `white-space:pre` CSS rule is required on the list container to prevent
* browsers from collapsing the whitespace in the output strings.
*
* ```js
* accounting.formatColumn([123.5, 3456.49, 777888.99, 12345678, -5432], "$ ");
* ```
*
* @method formatColumn
* @for accounting
* @param {Array<Number>} list An array of numbers to format
* @param {Object|String} [symbol="$"] String with the currency symbol. For conveniency if can be an object containing all the options of the method.
* @param {Integer} [precision=2] Number of decimal digits
* @param {String} [thousand=','] String with the thousands separator.
* @param {String} [decimal="."] String with the decimal separator.
* @param {String} [format="%s%v"] String with the format to apply, where %s is the currency symbol and %v is the value.
* @return {Array<String>} array of accouting-formatted number strings of same length
*/
export default function formatColumn(list, symbol, precision, thousand, decimal, format) {
if (!list) {
return [];
}
// 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,
},
currency
);
// Check format (returns object with pos, neg and zero), only need pos for now:
var formats = checkCurrencyFormat(opts.format);
// Whether to pad at start of string or after currency symbol:
var padAfterSymbol = formats.pos.indexOf('%s') < formats.pos.indexOf('%v');
// Store value for the length of the longest string in the column:
var maxLength = 0;
// Format the list according to options, store the length of the longest string:
var formatted = list.map(function (val) {
if (isArray(val)) {
// Recursively format columns if list is a multi-dimensional array:
return formatColumn(val, opts);
} else {
// Clean up the value
val = unformat(val);
// Choose which format to use for this value (pos, neg or zero):
var useFormat = val > 0 ? formats.pos : val < 0 ? formats.neg : formats.zero;
// Format this value, push into formatted list and save the length:
var fVal = useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(val), checkPrecision(opts.precision), opts.thousand, opts.decimal));
if (fVal.length > maxLength) {
maxLength = fVal.length;
}
return fVal;
}
});
// Pad each number in the list and send back the column of numbers:
return formatted.map(function (val) {
// Only if this is a string (not a nested array, which would have already been padded):
if (typeof val === 'string' && val.length < maxLength) {
// Depending on symbol position, pad after symbol or at index 0:
return padAfterSymbol ? val.replace(opts.symbol, opts.symbol + new Array(maxLength - val.length + 1).join(' ')) : new Array(maxLength - val.length + 1).join(' ') + val;
}
return val;
});
}