summaryrefslogtreecommitdiff
path: root/lib/dojo/number.js.uncompressed.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dojo/number.js.uncompressed.js')
-rw-r--r--lib/dojo/number.js.uncompressed.js553
1 files changed, 553 insertions, 0 deletions
diff --git a/lib/dojo/number.js.uncompressed.js b/lib/dojo/number.js.uncompressed.js
new file mode 100644
index 000000000..0f52cc1e6
--- /dev/null
+++ b/lib/dojo/number.js.uncompressed.js
@@ -0,0 +1,553 @@
+define("dojo/number", [/*===== "./_base/declare", =====*/ "./_base/lang", "./i18n", "./i18n!./cldr/nls/number", "./string", "./regexp"],
+ function(/*===== declare, =====*/ lang, i18n, nlsNumber, dstring, dregexp){
+
+// module:
+// dojo/number
+
+var number = {
+ // summary:
+ // localized formatting and parsing routines for Number
+};
+lang.setObject("dojo.number", number);
+
+/*=====
+number.__FormatOptions = declare(null, {
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization. Literal characters in patterns are not supported.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // places: Number?
+ // fixed number of decimal places to show. This overrides any
+ // information in the provided pattern.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means do not round.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // fractional: Boolean?
+ // If false, show no decimal places, overriding places and pattern settings.
+});
+=====*/
+
+number.format = function(/*Number*/ value, /*number.__FormatOptions?*/ options){
+ // summary:
+ // Format a Number as a String, using locale-specific settings
+ // description:
+ // Create a string from a Number using a known localized pattern.
+ // Formatting patterns appropriate to the locale are chosen from the
+ // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
+ // delimiters.
+ // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
+ // value:
+ // the number to be formatted
+
+ options = lang.mixin({}, options || {});
+ var locale = i18n.normalizeLocale(options.locale),
+ bundle = i18n.getLocalization("dojo.cldr", "number", locale);
+ options.customs = bundle;
+ var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+ if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
+ return number._applyPattern(value, pattern, options); // String
+};
+
+//number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
+number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
+
+number._applyPattern = function(/*Number*/ value, /*String*/ pattern, /*number.__FormatOptions?*/ options){
+ // summary:
+ // Apply pattern to format value as a string using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted.
+ // pattern:
+ // a pattern string as described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // options: number.__FormatOptions?
+ // _applyPattern is usually called via `dojo/number.format()` which
+ // populates an extra property in the options parameter, "customs".
+ // The customs object specifies group and decimal parameters if set.
+
+ //TODO: support escapes
+ options = options || {};
+ var group = options.customs.group,
+ decimal = options.customs.decimal,
+ patternList = pattern.split(';'),
+ positivePattern = patternList[0];
+ pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
+
+ //TODO: only test against unescaped
+ if(pattern.indexOf('%') != -1){
+ value *= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ value *= 1000; // per mille
+ }else if(pattern.indexOf('\u00a4') != -1){
+ group = options.customs.currencyGroup || group;//mixins instead?
+ decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
+ pattern = pattern.replace(/\u00a4{1,3}/, function(match){
+ var prop = ["symbol", "currency", "displayName"][match.length-1];
+ return options[prop] || options.currency || "";
+ });
+ }else if(pattern.indexOf('E') != -1){
+ throw new Error("exponential notation not supported");
+ }
+
+ //TODO: support @ sig figs?
+ var numberPatternRE = number._numberPatternRE;
+ var numberPattern = positivePattern.match(numberPatternRE);
+ if(!numberPattern){
+ throw new Error("unable to find a number expression in pattern: "+pattern);
+ }
+ if(options.fractional === false){ options.places = 0; }
+ return pattern.replace(numberPatternRE,
+ number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
+};
+
+number.round = function(/*Number*/ value, /*Number?*/ places, /*Number?*/ increment){
+ // summary:
+ // Rounds to the nearest value with the given number of decimal places, away from zero
+ // description:
+ // Rounds to the nearest value with the given number of decimal places, away from zero if equal.
+ // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
+ // fractional increments also, such as the nearest quarter.
+ // NOTE: Subject to floating point errors. See dojox/math/round for experimental workaround.
+ // value:
+ // The number to round
+ // places:
+ // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding.
+ // Must be non-negative.
+ // increment:
+ // Rounds next place to nearest value of increment/10. 10 by default.
+ // example:
+ // | >>> number.round(-0.5)
+ // | -1
+ // | >>> number.round(162.295, 2)
+ // | 162.29 // note floating point error. Should be 162.3
+ // | >>> number.round(10.71, 0, 2.5)
+ // | 10.75
+ var factor = 10 / (increment || 10);
+ return (factor * +value).toFixed(places) / factor; // Number
+};
+
+if((0.9).toFixed() == 0){
+ // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
+ // is just after the rounding place and is >=5
+ var round = number.round;
+ number.round = function(v, p, m){
+ var d = Math.pow(10, -p || 0), a = Math.abs(v);
+ if(!v || a >= d){
+ d = 0;
+ }else{
+ a /= d;
+ if(a < 0.5 || a >= 0.95){
+ d = 0;
+ }
+ }
+ return round(v, p, m) + (v > 0 ? d : -d);
+ };
+
+ // Use "doc hint" so the doc parser ignores this new definition of round(), and uses the one above.
+ /*===== number.round = round; =====*/
+}
+
+/*=====
+number.__FormatAbsoluteOptions = declare(null, {
+ // decimal: String?
+ // the decimal separator
+ // group: String?
+ // the group separator
+ // places: Number|String?
+ // number of decimal places. the range "n,m" will format to m places.
+ // round: Number?
+ // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
+ // means don't round.
+});
+=====*/
+
+number._formatAbsolute = function(/*Number*/ value, /*String*/ pattern, /*number.__FormatAbsoluteOptions?*/ options){
+ // summary:
+ // Apply numeric pattern to absolute value using options. Gives no
+ // consideration to local customs.
+ // value:
+ // the number to be formatted, ignores sign
+ // pattern:
+ // the number portion of a pattern (e.g. `#,##0.00`)
+ options = options || {};
+ if(options.places === true){options.places=0;}
+ if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
+
+ var patternParts = pattern.split("."),
+ comma = typeof options.places == "string" && options.places.indexOf(","),
+ maxPlaces = options.places;
+ if(comma){
+ maxPlaces = options.places.substring(comma + 1);
+ }else if(!(maxPlaces >= 0)){
+ maxPlaces = (patternParts[1] || []).length;
+ }
+ if(!(options.round < 0)){
+ value = number.round(value, maxPlaces, options.round);
+ }
+
+ var valueParts = String(Math.abs(value)).split("."),
+ fractional = valueParts[1] || "";
+ if(patternParts[1] || options.places){
+ if(comma){
+ options.places = options.places.substring(0, comma);
+ }
+ // Pad fractional with trailing zeros
+ var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
+ if(pad > fractional.length){
+ valueParts[1] = dstring.pad(fractional, pad, '0', true);
+ }
+
+ // Truncate fractional
+ if(maxPlaces < fractional.length){
+ valueParts[1] = fractional.substr(0, maxPlaces);
+ }
+ }else{
+ if(valueParts[1]){ valueParts.pop(); }
+ }
+
+ // Pad whole with leading zeros
+ var patternDigits = patternParts[0].replace(',', '');
+ pad = patternDigits.indexOf("0");
+ if(pad != -1){
+ pad = patternDigits.length - pad;
+ if(pad > valueParts[0].length){
+ valueParts[0] = dstring.pad(valueParts[0], pad);
+ }
+
+ // Truncate whole
+ if(patternDigits.indexOf("#") == -1){
+ valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
+ }
+ }
+
+ // Add group separators
+ var index = patternParts[0].lastIndexOf(','),
+ groupSize, groupSize2;
+ if(index != -1){
+ groupSize = patternParts[0].length - index - 1;
+ var remainder = patternParts[0].substr(0, index);
+ index = remainder.lastIndexOf(',');
+ if(index != -1){
+ groupSize2 = remainder.length - index - 1;
+ }
+ }
+ var pieces = [];
+ for(var whole = valueParts[0]; whole;){
+ var off = whole.length - groupSize;
+ pieces.push((off > 0) ? whole.substr(off) : whole);
+ whole = (off > 0) ? whole.slice(0, off) : "";
+ if(groupSize2){
+ groupSize = groupSize2;
+ delete groupSize2;
+ }
+ }
+ valueParts[0] = pieces.reverse().join(options.group || ",");
+
+ return valueParts.join(options.decimal || ".");
+};
+
+/*=====
+number.__RegexpOptions = declare(null, {
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
+ // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
+ // places: Number|String?
+ // number of decimal places to accept: Infinity, a positive number, or
+ // a range "n,m". Defined by pattern or Infinity if pattern not provided.
+});
+=====*/
+number.regexp = function(/*number.__RegexpOptions?*/ options){
+ // summary:
+ // Builds the regular needed to parse a number
+ // description:
+ // Returns regular expression with positive and negative match, group
+ // and decimal separators
+ return number._parseInfo(options).regexp; // String
+};
+
+number._parseInfo = function(/*Object?*/ options){
+ options = options || {};
+ var locale = i18n.normalizeLocale(options.locale),
+ bundle = i18n.getLocalization("dojo.cldr", "number", locale),
+ pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
+//TODO: memoize?
+ group = bundle.group,
+ decimal = bundle.decimal,
+ factor = 1;
+
+ if(pattern.indexOf('%') != -1){
+ factor /= 100;
+ }else if(pattern.indexOf('\u2030') != -1){
+ factor /= 1000; // per mille
+ }else{
+ var isCurrency = pattern.indexOf('\u00a4') != -1;
+ if(isCurrency){
+ group = bundle.currencyGroup || group;
+ decimal = bundle.currencyDecimal || decimal;
+ }
+ }
+
+ //TODO: handle quoted escapes
+ var patternList = pattern.split(';');
+ if(patternList.length == 1){
+ patternList.push("-" + patternList[0]);
+ }
+
+ var re = dregexp.buildGroupRE(patternList, function(pattern){
+ pattern = "(?:"+dregexp.escapeString(pattern, '.')+")";
+ return pattern.replace(number._numberPatternRE, function(format){
+ var flags = {
+ signed: false,
+ separator: options.strict ? group : [group,""],
+ fractional: options.fractional,
+ decimal: decimal,
+ exponent: false
+ },
+
+ parts = format.split('.'),
+ places = options.places;
+
+ // special condition for percent (factor != 1)
+ // allow decimal places even if not specified in pattern
+ if(parts.length == 1 && factor != 1){
+ parts[1] = "###";
+ }
+ if(parts.length == 1 || places === 0){
+ flags.fractional = false;
+ }else{
+ if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
+ if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
+ if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
+ flags.places = places;
+ }
+ var groups = parts[0].split(',');
+ if(groups.length > 1){
+ flags.groupSize = groups.pop().length;
+ if(groups.length > 1){
+ flags.groupSize2 = groups.pop().length;
+ }
+ }
+ return "("+number._realNumberRegexp(flags)+")";
+ });
+ }, true);
+
+ if(isCurrency){
+ // substitute the currency symbol for the placeholder in the pattern
+ re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
+ var prop = ["symbol", "currency", "displayName"][target.length-1],
+ symbol = dregexp.escapeString(options[prop] || options.currency || "");
+ before = before ? "[\\s\\xa0]" : "";
+ after = after ? "[\\s\\xa0]" : "";
+ if(!options.strict){
+ if(before){before += "*";}
+ if(after){after += "*";}
+ return "(?:"+before+symbol+after+")?";
+ }
+ return before+symbol+after;
+ });
+ }
+
+//TODO: substitute localized sign/percent/permille/etc.?
+
+ // normalize whitespace and return
+ return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
+};
+
+/*=====
+number.__ParseOptions = declare(null, {
+ // pattern: String?
+ // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // with this string. Default value is based on locale. Overriding this property will defeat
+ // localization. Literal characters in patterns are not supported.
+ // type: String?
+ // choose a format type based on the locale from the following:
+ // decimal, scientific (not yet supported), percent, currency. decimal by default.
+ // locale: String?
+ // override the locale used to determine formatting rules
+ // strict: Boolean?
+ // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
+ // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
+ // fractional: Boolean|Array?
+ // Whether to include the fractional portion, where the number of decimal places are implied by pattern
+ // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
+});
+=====*/
+number.parse = function(/*String*/ expression, /*number.__ParseOptions?*/ options){
+ // summary:
+ // Convert a properly formatted string to a primitive Number, using
+ // locale-specific settings.
+ // description:
+ // Create a Number from a string using a known localized pattern.
+ // Formatting patterns are chosen appropriate to the locale
+ // and follow the syntax described by
+ // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
+ // Note that literal characters in patterns are not supported.
+ // expression:
+ // A string representation of a Number
+ var info = number._parseInfo(options),
+ results = (new RegExp("^"+info.regexp+"$")).exec(expression);
+ if(!results){
+ return NaN; //NaN
+ }
+ var absoluteMatch = results[1]; // match for the positive expression
+ if(!results[1]){
+ if(!results[2]){
+ return NaN; //NaN
+ }
+ // matched the negative pattern
+ absoluteMatch =results[2];
+ info.factor *= -1;
+ }
+
+ // Transform it to something Javascript can parse as a number. Normalize
+ // decimal point and strip out group separators or alternate forms of whitespace
+ absoluteMatch = absoluteMatch.
+ replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
+ replace(info.decimal, ".");
+ // Adjust for negative sign, percent, etc. as necessary
+ return absoluteMatch * info.factor; //Number
+};
+
+/*=====
+number.__RealNumberRegexpFlags = declare(null, {
+ // places: Number?
+ // The integer number of decimal places or a range given as "n,m". If
+ // not given, the decimal part is optional and the number of places is
+ // unlimited.
+ // decimal: String?
+ // A string for the character used as the decimal point. Default
+ // is ".".
+ // fractional: Boolean|Array?
+ // Whether decimal places are used. Can be true, false, or [true,
+ // false]. Default is [true, false] which means optional.
+ // exponent: Boolean|Array?
+ // Express in exponential notation. Can be true, false, or [true,
+ // false]. Default is [true, false], (i.e. will match if the
+ // exponential part is present are not).
+ // eSigned: Boolean|Array?
+ // The leading plus-or-minus sign on the exponent. Can be true,
+ // false, or [true, false]. Default is [true, false], (i.e. will
+ // match if it is signed or unsigned). flags in regexp.integer can be
+ // applied.
+});
+=====*/
+
+number._realNumberRegexp = function(/*__RealNumberRegexpFlags?*/ flags){
+ // summary:
+ // Builds a regular expression to match a real number in exponential
+ // notation
+
+ // assign default values to missing parameters
+ flags = flags || {};
+ //TODO: use mixin instead?
+ if(!("places" in flags)){ flags.places = Infinity; }
+ if(typeof flags.decimal != "string"){ flags.decimal = "."; }
+ if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
+ if(!("exponent" in flags)){ flags.exponent = [true, false]; }
+ if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
+
+ var integerRE = number._integerRegexp(flags),
+ decimalRE = dregexp.buildGroupRE(flags.fractional,
+ function(q){
+ var re = "";
+ if(q && (flags.places!==0)){
+ re = "\\" + flags.decimal;
+ if(flags.places == Infinity){
+ re = "(?:" + re + "\\d+)?";
+ }else{
+ re += "\\d{" + flags.places + "}";
+ }
+ }
+ return re;
+ },
+ true
+ );
+
+ var exponentRE = dregexp.buildGroupRE(flags.exponent,
+ function(q){
+ if(q){ return "([eE]" + number._integerRegexp({ signed: flags.eSigned}) + ")"; }
+ return "";
+ }
+ );
+
+ var realRE = integerRE + decimalRE;
+ // allow for decimals without integers, e.g. .25
+ if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
+ return realRE + exponentRE; // String
+};
+
+/*=====
+number.__IntegerRegexpFlags = declare(null, {
+ // signed: Boolean?
+ // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
+ // Default is `[true, false]`, (i.e. will match if it is signed
+ // or unsigned).
+ // separator: String?
+ // The character used as the thousands separator. Default is no
+ // separator. For more than one symbol use an array, e.g. `[",", ""]`,
+ // makes ',' optional.
+ // groupSize: Number?
+ // group size between separators
+ // groupSize2: Number?
+ // second grouping, where separators 2..n have a different interval than the first separator (for India)
+});
+=====*/
+
+number._integerRegexp = function(/*number.__IntegerRegexpFlags?*/ flags){
+ // summary:
+ // Builds a regular expression that matches an integer
+
+ // assign default values to missing parameters
+ flags = flags || {};
+ if(!("signed" in flags)){ flags.signed = [true, false]; }
+ if(!("separator" in flags)){
+ flags.separator = "";
+ }else if(!("groupSize" in flags)){
+ flags.groupSize = 3;
+ }
+
+ var signRE = dregexp.buildGroupRE(flags.signed,
+ function(q){ return q ? "[-+]" : ""; },
+ true
+ );
+
+ var numberRE = dregexp.buildGroupRE(flags.separator,
+ function(sep){
+ if(!sep){
+ return "(?:\\d+)";
+ }
+
+ sep = dregexp.escapeString(sep);
+ if(sep == " "){ sep = "\\s"; }
+ else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
+
+ var grp = flags.groupSize, grp2 = flags.groupSize2;
+ //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933
+ if(grp2){
+ var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
+ return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+ }
+ return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
+ },
+ true
+ );
+
+ return signRE + numberRE; // String
+};
+
+return number;
+});