Code content and
The accounting. js code is as follows:
Copy codeThe Code is as follows :/*!
* Accounting. js v0.3.2
* Copyright 2011, Joss Crowcroft
*
* Freely distributable under the MIT license.
* Portions of accounting. js are wrongly red or borrowed from underscore. js
*
* Full details and documentation:
* Http://josscrowcroft.github.com/accounting.js/
*/
(Function (root, undefined ){
/* --- Setup ---*/
// Create the local library object, to be exported or referenced globally later
Var lib = {};
// Current version
Lib. version = '0. 3.2 ';
/* --- Exposed settings ---*/
// The library's settings configuration object. Contains default parameters
// Currency and number formatting
Lib. 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 :"."
}
};
/* --- Internal Helper Methods ---*/
// Store reference to possibly-available ECMAScript 5 methods for later
Var nativeMap = Array. prototype. map,
NativeIsArray = Array. isArray,
ToString = Object. prototype. toString;
/**
* Tests whether supplied parameter is a string
* From underscore. js
*/
Function isString (obj ){
Return !! (Obj = ''| (obj & obj. charCodeAt & obj. substr ));
}
/**
* Tests whether supplied parameter is a string
* From underscore. js, delegates to ECMA5's native Array. isArray
*/
Function isArray (obj ){
Return nativeIsArray? NativeIsArray (obj): toString. call (obj) = '[object Array]';
}
/**
* Tests whether supplied parameter is a true object
*/
Function isObject (obj ){
Return obj & toString. call (obj) = '[object Object]';
}
/**
* Extends an object with a defaults object, similar to underscore's _. defaults
*
* Used for processing acting parameter handling from API methods
*/
Function defaults (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;
}
/**
* Implementation of 'array. map () 'for iteration loops
*
* Returns a new Array as a result of calling 'iterator' on each array value.
* Defers to native Array. map if available
*/
Function map (obj, iterator, context ){
Var results = [], I, j;
If (! Obj) return results;
// Use native. map method if it exists:
If (nativeMap & obj. map === nativeMap) return obj. map (iterator, context );
// Fallback for native. map:
For (I = 0, j = obj. length; I <j; I ++ ){
Results [I] = iterator. call (context, obj [I], I, obj );
}
Return results;
}
/**
* Check and normalise the value of precision (must be positive integer)
*/
Function checkPrecision (val, base ){
Val = Math. round (Math. abs (val ));
Return isNaN (val )? Base: val;
}
/**
* 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
*/
Function checkCurrencyFormat (format ){
Var defaults = lib. settings. currency. format;
// Allow function as format parameter (shocould 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: lib. settings. currency. format = {
Pos: defaults,
Neg: defaults. replace ("% v", "-% v "),
Zero: defaults
};
}
// Otherwise, assume format was fine:
Return format;
}
/* --- API Methods ---*/
/**
* Takes a string/array of strings, removes all formatting/cruft and returns the raw float value
* Alias: accounting. 'parse (string )'
*
* Decimal must be encoded in the regular expression to match floats (defaults
* 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
*/
Var unformat = lib. unformat = lib. parse = 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 cocould be set to eg. "," in opts:
Decimal = decimal | lib. settings. number. decimal;
// Build regex to strip out everything blocks t digits, decimal point and minus sign:
Var regex = new RegExp ("[^ 0-" + decimal + "]", ["g"]),
Unformatted = parseFloat (
("" + Value)
. Replace (/\ (. *) \)/, "-$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;
};
/**
* 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.
*/
Var toFixed = lib. toFixed = function (value, precision ){
Precision = checkPrecision (precision, lib. settings. number. precision );
Var power = Math. pow (10, precision );
// Multiply up by precision, round accurately, then divide and use native toFixed ():
Return (Math. round (lib. unformat (value) * power)/power). toFixed (precision );
};
/**
* Format a number, with comma-separated thousands and custom precision/decimal places
*
* Localise by overriding the precision and thousand/decimal separators
* 2nd parameter 'height' can be an object matching 'settings. number'
*/
Var formatNumber = lib. 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
}),
Lib. 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
*/
Var formatMoney = lib. 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
}),
Lib. 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 ));
};
/**
* Format a list of numbers into an accounting column, padding with whitespace
* To line up currency symbols, thousand separators and decimals places
*
* List shoshould be an array of numbers
* Second parameter can be an object containing keys that matches the params
*
* Returns array of accouting-formatted number strings of same length
*
* NB: 'white-space: pre' CSS rule is required on the list container to prevent
* Browsers from collapsing the whitespace in the output strings.
*/
Lib. formatColumn = function (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
}),
Lib. settings. currency
),
// Check format (returns object with pos, neg and zero), only need pos for now:
Formats = checkCurrencyFormat (opts. format ),
// Whether to pad at start of string or after currency symbol:
PadAfterSymbol = formats. pos. indexOf ("% s") <formats. pos. indexOf ("% v ")? True: false,
// Store value for the length of the longest string in the column:
MaxLength = 0,
// Format the list according to options, store the length of the longest string:
Formatted = map (list, function (val, I ){
If (isArray (val )){
// Recursively format columns if list is a multi-dimen1_array:
Return lib. 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:
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 map (formatted, function (val, I ){
// Only if this is a string (not a nested array, which wowould have already been padded ):
If (isString (val) & 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;
});
};
/* --- Module Definition ---*/
// Export accounting for CommonJS. If being loaded as an AMD module, define it as such.
// Otherwise, just add 'account' to the global object
If (typeof exports! = 'Undefined '){
If (typeof module! = 'Undefined' & module. exports ){
Exports = module. exports = lib;
}
Exports. accounting = lib;
} Else if (typeof define ==== 'function' & define. amd ){
// Return the library as an AMD module:
Define ([], function (){
Return lib;
});
} Else {
// Use accounting. noConflict to restore 'accounting' back to its original value.
// Returns a reference to the library's 'accounting' object;
// E.g. 'var numbers = accounting. noConflict ();'
Lib. noConflict = (function (oldAccounting ){
Return function (){
// Reset the value of the root's 'accounting' variable:
Root. accounting = oldAccounting;
// Delete the noConflict method:
Lib. noConflict = undefined;
// Return reference to the library to re-assign it:
Return lib;
};
}) (Root. accounting );
// Declare 'fx 'on the root (global/window) object:
Root ['accounting'] = lib;
}
// Root will be 'window' in browser or 'global' on the server:
} (This ));
Https://raw.github.com/josscrowcroft/accounting.js/master/accounting.js
Use instance
FormatMoneyCopy codeThe Code is as follows: formatMoney
// Default usage:
Accounting. formatMoney (12345678); // $12,345,678.00
// European formatting (custom symbol and separators), cocould also use options object as second param:
Accounting. formatMoney (4999.99, "", 2, ".", ","); // 4.999, 99
// Negative values are formatted nicely, too:
Accounting. formatMoney (-500000, "£", 0); // £-500,000
// Simple 'format' string allows control of symbol position [% v = value, % s = symbol]:
Accounting. formatMoney (5318008, {symbol: "GBP", format: "% v % s"}); // 5,318,008.00 GBP
FormatNumberCopy codeThe Code is as follows: accounting. formatNumber (5318008); // 5,318,008
Accounting. formatNumber (9876543.21, 3, ""); // 9 876 543.210
UnformatCopy codeThe Code is as follows: accounting. unformat ("£ 12,345,678.90 GBP"); // 12345678.9
Official Demo: http://josscrowcroft.github.com/accounting.js/
Accounting. js