ares-ide
Version:
A browser-based code editor and UI designer for Enyo 2 projects
231 lines (200 loc) • 8.69 kB
JavaScript
/*$
* @number format.js
* @fileOverview This file has the implementation of the Number formatter object
*
*/
/*globals G11n enyo */
//* @public
/**
Creates a formatter (_NumberFmt_) object that formats numbers according to
the passed-in options. Once the formatter is created, it is intended to be
immutable, so you can create multiple formatters for different purposes and
they will not conflict with each other.
The _options_ object may include any of the following properties:
* locale: The locale of the formatter. If this is not specified, the
current _formatLocale_ is used as a default.
* style: One of "number", "percent", or "currency". If this is not
specified, the default is "number". This formats numbers according to
the locale's conventions for formatting floating point numbers,
percentages, and monetary amounts, respectively.
* currency: The ISO 4217 three-letter code for the currency to format. The
_currency_ property affects the currency sign used to identify the
currency in the output string. It can interact with the _locale_ in that
the currency sign may be placed before or after the amount and with or
without space, depending on the locale. For example, both Germany and
Ireland use the same currency (the Euro), but in Ireland, amounts are
written as "€5.34", whereas in Germany, the same amount is written as
"5,34 €".
If a locale spec is given as the value of this property and the legal
currency for the named locale can be determined, then that currency will
be used as the default.
Note that this property has no effect unless the _style_ property is set
to "currency".
* currencyStyle: This property may have one of the following values: "iso"
or "common". The "iso" style causes the currency to be formatted using
the ISO 4217 code as the currency sign. The "common" style causes the
currency to be formatted using the common currency sign for the locale.
For example, the "iso" style in the German locale would be "5,34 EUR",
while the "common" style would be "5,34 €". In Ireland, the "iso" style
would be "EUR 5.34" and the "common" style would be "€5.34".
If no value is specified for this property, "common" is used as the
default.
* fractionDigits: The number of digits to show after the decimal. If this is
not specified, all digits are shown in the "number" and "percent"
styles. With the "currency" style, the default number of fractional
digits shown is the number that is commonly used for the currency being
formatted, which is usually 0, 2 or 3. When a number being formatted has
more digits than the fractionDigits property allows, the number is
rounded to fit within that number of fractional digits.
*/
enyo.g11n.NumberFmt = function(options) {
var formatHash,
currencyInfo,
currencyName,
currencyEntry,
currencyLocale,
template,
otherFormatHash;
if (typeof options === "number") {
this.fractionDigits = options;
} else if (options && typeof(options.fractionDigits) === 'number') {
this.fractionDigits = options.fractionDigits;
}
if (!options || !options.locale) {
this.locale = enyo.g11n.formatLocale();
} else if (typeof(options.locale) === 'string') {
this.locale = new enyo.g11n.Locale(options.locale);
} else {
this.locale = options.locale;
}
// enyo.log("NumberFmt: locale is " + this.locale);
this.style = (options && options.style) || "number";
formatHash = enyo.g11n.Utils.getJsonFile({
root: enyo.g11n.Utils._getEnyoRoot(),
path: "base/formats",
locale: this.locale,
type: "region"
});
if (this.style === "currency") {
currencyName = (options && options.currency) || (formatHash && formatHash.currency && formatHash.currency.name);
if (currencyName) {
currencyName = currencyName.toUpperCase();
this.currencyStyle = (options && options.currencyStyle === "iso") ? "iso" : "common";
// enyo.log("currentName is " + currencyName + " and currencyStyle is " + this.currencyStyle);
currencyInfo = enyo.g11n.Utils.getNonLocaleFile({
root: enyo.g11n.Utils._getEnyoRoot(),
path: "base/number_data/iso4217.json"
});
if (currencyInfo) {
currencyEntry = currencyInfo[currencyName];
if (!currencyEntry) {
// invalid currency name... see if it is a locale name instead
currencyLocale = new enyo.g11n.Locale(currencyName);
otherFormatHash = enyo.g11n.Utils.getJsonFile({
root: enyo.g11n.Utils._getEnyoRoot(),
path: "base/formats",
locale: currencyLocale,
type: "region"
});
if (otherFormatHash) {
currencyName = otherFormatHash.currency && otherFormatHash.currency.name;
currencyEntry = currencyInfo[currencyName];
}
}
if (!currencyEntry) {
// still not there? try using the currency for the current locale
currencyName = formatHash && formatHash.currency && formatHash.currency.name;
currencyEntry = currencyInfo[currencyName];
}
if (currencyEntry) {
this.sign = this.currencyStyle !== "iso" ? currencyEntry.sign : currencyName;
this.fractionDigits = (options && typeof(options.fractionDigits) === 'number') ? options.fractionDigits : currencyEntry.digits;
} else {
// okay, give up and format as a plain number instead
this.style = "number";
}
} else {
// no currency info -- probably not passed a currency name... try the currency of this locale, otherwise
// don't format
currencyName = (formatHash && formatHash.currency && formatHash.currency.name);
this.sign = currencyName;
}
} else {
// no currency name to use, so just format this amount as an ISO format using the current locale
currencyName = (formatHash && formatHash.currency && formatHash.currency.name);
this.sign = currencyName;
//enyo.log("NumberFmt: no currency name specified. Using: " + currencyName);
}
if (currencyName) {
// enyo.log("currency sign is " + this.sign);
template = (formatHash && formatHash.currency && formatHash.currency[this.currencyStyle]) || "#{sign} #{amt}";
// enyo.log("currency template is " + template);
this.currencyTemplate = new enyo.g11n.Template(template);
} else {
// can't find the currency name and don't have a current locale -- okay, just format this amount as a number then.
this.style = "number";
}
}
if (formatHash) {
this.decimal = formatHash.numberDecimal || ".";
this.divider = formatHash.numberDivider || ",";
if (!formatHash.dividerIndex) {
this.numberGroupRegex = /(\d+)(\d{3})/;
} else if (formatHash.dividerIndex === 4) {
this.numberGroupRegex = /(\d+)(\d{4})/;
} else {
this.numberGroupRegex = /(\d+)(\d{3})/;
}
this.percentageSpace = formatHash.percentageSpace;
} else {
// default is US/English style
this.decimal = ".";
this.divider = ",";
this.numberGroupRegex = /(\d+)(\d{3})/;
this.percentageSpace = false;
}
this.numberGroupRegex.compile(this.numberGroupRegex);
enyo.g11n.Utils.releaseAllJsonFiles();
};
/**
Converts a passed-in number to a string, using the proper locale-based
format for numbers. If the parameter is passed in as a string containing a
number, it is first parsed into a number before being reformatted as a
string and returned. If the parameter is neither a number nor a string
containing a valid number, the value "undefined" is returned.
*/
enyo.g11n.NumberFmt.prototype.format = function(number) {
try {
var rawFormat, parts, wholeNumberPart, num;
if (typeof(number) === 'string') {
number = parseFloat(number);
}
if (isNaN(number)) {
return undefined;
}
if (typeof(this.fractionDigits) !== "undefined") {
rawFormat = number.toFixed(this.fractionDigits);
} else {
rawFormat = number.toString();
}
parts = rawFormat.split(".");
wholeNumberPart = parts[0];
while (this.divider && this.numberGroupRegex.test(wholeNumberPart)) {
wholeNumberPart = wholeNumberPart.replace(this.numberGroupRegex, '$1' + this.divider + '$2');
}
parts[0] = wholeNumberPart;
num = parts.join(this.decimal);
if (this.style === 'currency' && this.currencyTemplate) {
num = this.currencyTemplate.evaluate({
amt: num,
sign: this.sign
});
} else if (this.style === 'percent') {
num += (this.percentageSpace? " %" : "%");
}
return num;
} catch(e) {
enyo.log("formatNumber error : " + e);
return (number || "0") + "." + (this.fractionDigits || "");
}
};