From f0cfe83e3725f9a3928da97a6e3085e79cb25309 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 18 Mar 2013 10:26:24 +0400 Subject: upgrade dojo to 1.8.3 (refs #570) --- lib/dojo/number.js.uncompressed.js | 553 +++++++++++++++++++++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 lib/dojo/number.js.uncompressed.js (limited to 'lib/dojo/number.js.uncompressed.js') 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; +}); -- cgit v1.2.3