devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
317 lines (243 loc) • 9.52 kB
JavaScript
"use strict";
var dependencyInjector = require("../core/utils/dependency_injector"),
inArray = require("../core/utils/array").inArray,
escapeRegExp = require("../core/utils/common").escapeRegExp,
each = require("../core/utils/iterator").each,
isPlainObject = require("../core/utils/type").isPlainObject,
ldmlNumber = require("./ldml/number"),
config = require("../core/config"),
errors = require("../core/errors");
var MAX_LARGE_NUMBER_POWER = 4,
DECIMAL_BASE = 10;
var NUMERIC_FORMATS = ["currency", "fixedpoint", "exponential", "percent", "decimal"];
var LargeNumberFormatPostfixes = {
1: 'K', // kilo
2: 'M', // mega
3: 'B', // billions
4: 'T' // tera
};
var LargeNumberFormatPowers = {
"largenumber": 'auto',
"thousands": 1,
"millions": 2,
"billions": 3,
"trillions": 4
};
var numberLocalization = dependencyInjector({
numericFormats: NUMERIC_FORMATS,
defaultLargeNumberFormatPostfixes: LargeNumberFormatPostfixes,
_parseNumberFormatString: function _parseNumberFormatString(formatType) {
var formatList,
formatObject = {};
if (!formatType || typeof formatType !== 'string') return;
formatList = formatType.toLowerCase().split(' ');
each(formatList, function (index, value) {
if (inArray(value, NUMERIC_FORMATS) > -1) {
formatObject.formatType = value;
} else if (value in LargeNumberFormatPowers) {
formatObject.power = LargeNumberFormatPowers[value];
}
});
if (formatObject.power && !formatObject.formatType) {
formatObject.formatType = 'fixedpoint';
}
if (formatObject.formatType) {
return formatObject;
}
},
_calculateNumberPower: function _calculateNumberPower(value, base, minPower, maxPower) {
var number = Math.abs(value),
power = 0;
if (number > 1) {
while (number && number >= base && (maxPower === undefined || power < maxPower)) {
power++;
number = number / base;
}
} else if (number > 0 && number < 1) {
while (number < 1 && (minPower === undefined || power > minPower)) {
power--;
number = number * base;
}
}
return power;
},
_getNumberByPower: function _getNumberByPower(number, power, base) {
var result = number;
while (power > 0) {
result = result / base;
power--;
}
while (power < 0) {
result = result * base;
power++;
}
return result;
},
_formatNumber: function _formatNumber(value, formatObject, formatConfig) {
var powerPostfix;
var result;
if (formatObject.power === 'auto') {
formatObject.power = this._calculateNumberPower(value, 1000, 0, MAX_LARGE_NUMBER_POWER);
}
if (formatObject.power) {
value = this._getNumberByPower(value, formatObject.power, 1000);
}
powerPostfix = this.defaultLargeNumberFormatPostfixes[formatObject.power] || '';
result = this._formatNumberCore(value, formatObject.formatType, formatConfig);
result = result.replace(/(\d|.$)(\D*)$/, "$1" + powerPostfix + "$2");
return result;
},
_formatNumberExponential: function _formatNumberExponential(value, formatConfig) {
var power = this._calculateNumberPower(value, DECIMAL_BASE),
number = this._getNumberByPower(value, power, DECIMAL_BASE),
powString;
if (formatConfig.precision === undefined) {
formatConfig.precision = 1;
}
if (number.toFixed(formatConfig.precision || 0) >= DECIMAL_BASE) {
power++;
number = number / DECIMAL_BASE;
}
powString = (power >= 0 ? '+' : '') + power.toString();
return this._formatNumberCore(number, 'fixedpoint', formatConfig) + 'E' + powString;
},
_addZeroes: function _addZeroes(value, precision) {
var multiplier = Math.pow(10, precision);
var sign = value < 0 ? "-" : "";
value = (Math.abs(value) * multiplier >>> 0) / multiplier;
var result = value.toString();
while (result.length < precision) {
result = "0" + result;
}
return sign + result;
},
_addGroupSeparators: function _addGroupSeparators(value) {
var parts = value.toString().split(".");
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, config().thousandsSeparator) + (parts[1] ? config().decimalSeparator + parts[1] : "");
},
_formatNumberCore: function _formatNumberCore(value, format, formatConfig) {
if (format === 'exponential') {
return this._formatNumberExponential(value, formatConfig);
}
if (format !== "decimal" && formatConfig.precision !== null) {
formatConfig.precision = formatConfig.precision || 0;
}
if (format === "percent") {
value = value * 100;
}
if (formatConfig.precision !== undefined) {
if (format === "decimal") {
value = this._addZeroes(value, formatConfig.precision);
} else {
value = formatConfig.precision === null ? value.toPrecision() : value.toFixed(formatConfig.precision);
}
}
if (format !== "decimal") {
value = this._addGroupSeparators(value);
} else {
value = value.toString().replace(".", config().decimalSeparator);
}
if (format === "percent") {
value += "%";
}
return value;
},
_normalizeFormat: function _normalizeFormat(format) {
if (!format) {
return {};
}
if (typeof format === "function") {
return format;
}
if (!isPlainObject(format)) {
format = {
type: format
};
}
return format;
},
_getSeparators: function _getSeparators() {
return {
decimalSeparator: this.getDecimalSeparator(),
thousandsSeparator: this.getThousandsSeparator()
};
},
getThousandsSeparator: function getThousandsSeparator() {
return this.format(1000, "fixedPoint")[1];
},
getDecimalSeparator: function getDecimalSeparator() {
return this.format(1.2, { type: "fixedPoint", precision: 1 })[1];
},
convertDigits: function convertDigits(value, toStandard) {
var digits = this.format(90, "decimal");
if (typeof value !== "string" || digits[1] === "0") {
return value;
}
var fromFirstDigit = toStandard ? digits[1] : "0",
toFirstDigit = toStandard ? "0" : digits[1],
fromLastDigit = toStandard ? digits[0] : "9",
regExp = new RegExp("[" + fromFirstDigit + "-" + fromLastDigit + "]", "g");
return value.replace(regExp, function (char) {
return String.fromCharCode(char.charCodeAt(0) + (toFirstDigit.charCodeAt(0) - fromFirstDigit.charCodeAt(0)));
});
},
getSign: function getSign(text, format) {
if (text.replace(/[^0-9\-]/g, "").charAt(0) === "-") {
return -1;
}
if (!format) {
return 1;
}
var separators = this._getSeparators(),
regExp = new RegExp("[0-9" + escapeRegExp(separators.decimalSeparator + separators.thousandsSeparator) + "]+", "g"),
negativeEtalon = this.format(-1, format).replace(regExp, "1"),
cleanedText = text.replace(regExp, "1");
return cleanedText === negativeEtalon ? -1 : 1;
},
format: function format(value, _format) {
if (typeof value !== "number") {
return value;
}
if (typeof _format === "number") {
return value;
}
_format = _format && _format.formatter || _format;
if (typeof _format === "function") {
return _format(value);
}
_format = this._normalizeFormat(_format);
if (!_format.type) {
_format.type = "decimal";
}
var numberConfig = this._parseNumberFormatString(_format.type);
if (!numberConfig) {
return this.convertDigits(ldmlNumber.getFormatter(_format.type, this._getSeparators())(value));
}
return this._formatNumber(value, numberConfig, _format);
},
parse: function parse(text, format) {
if (!text) {
return;
}
if (format && format.parser) {
return format.parser(text);
}
text = this.convertDigits(text, true);
if (format && typeof format !== "string") {
errors.log("W0011");
}
var decimalSeparator = this.getDecimalSeparator(),
regExp = new RegExp("[^0-9" + escapeRegExp(decimalSeparator) + "]", "g"),
cleanedText = text.replace(regExp, "").replace(decimalSeparator, ".").replace(/\.$/g, ""),
parsed = +cleanedText;
cleanedText = cleanedText.replace(/^\./g, "");
if (cleanedText.length > 15) {
return NaN;
}
if (cleanedText === "") {
return null;
}
return parsed * this.getSign(text, format);
}
});
module.exports = numberLocalization;