Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojo.number"] = true;dojo.provide("dojo.number");dojo.require("dojo.i18n");dojo.requireLocalization("dojo.cldr", "number", null, "zh-cn,en,en-ca,zh-tw,en-us,it,ja-jp,ROOT,de-de,es-es,fr,pt,ko-kr,es,de");dojo.require("dojo.string");dojo.require("dojo.regexp");/*=====dojo.number.__formatOptions = function(kwArgs){// pattern: String?// override formatting pattern with this string (see// dojo.number._applyPattern)// type: String?// choose a format type based on the locale from the following:// decimal, scientific, 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 don't round.// currency: String?// iso4217 currency code// symbol: String?// localized currency symbol// locale: String?// override the locale used to determine formatting rules}=====*/dojo.number.format = function(/*Number*/value, /*dojo.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// CLDR http://unicode.org/cldr as well as the appropriate symbols and// delimiters. See http://www.unicode.org/reports/tr35/#Number_Elements// value:// the number to be formatted. If not a valid JavaScript number,// return null.options = dojo.mixin({}, options || {});var locale = dojo.i18n.normalizeLocale(options.locale);var bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);options.customs = bundle;var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];if(isNaN(value)){ return null; } // nullreturn dojo.number._applyPattern(value, pattern, options); // String};//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enoughdojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enoughdojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.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 in// http://www.unicode.org/reports/tr35/#Number_Format_Patterns// options: dojo.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 escapesoptions = options || {};var group = options.customs.group;var decimal = options.customs.decimal;var patternList = pattern.split(';');var positivePattern = patternList[0];pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);//TODO: only test against unescapedif(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 = dojo.number._numberPatternRE;var numberPattern = positivePattern.match(numberPatternRE);if(!numberPattern){throw new Error("unable to find a number expression in pattern: "+pattern);}return pattern.replace(numberPatternRE,dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places}));}dojo.number.round = function(/*Number*/value, /*Number*/places, /*Number?*/multiple){// summary:// Rounds the number at the given number of places// value:// the number to round// places:// the number of decimal places where rounding takes place// multiple:// rounds next place to nearest multiplevar pieces = String(value).split(".");var length = (pieces[1] && pieces[1].length) || 0;if(length > places){var factor = Math.pow(10, places);if(multiple > 0){factor *= 10/multiple;places++;} //FIXMEvalue = Math.round(value * factor)/factor;// truncate to remove any residual floating point valuespieces = String(value).split(".");length = (pieces[1] && pieces[1].length) || 0;if(length > places){pieces[1] = pieces[1].substr(0, places);value = Number(pieces.join("."));}}return value; //Number}/*=====dojo.number.__formatAbsoluteOptions = function(kwArgs){// decimal: String?// the decimal separator// group: String?// the group separator// places: Integer?// number of decimal places// round: Number?// 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1// means don't round.}=====*/dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.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 limitvar patternParts = pattern.split(".");var maxPlaces = (options.places >= 0) ? options.places : (patternParts[1] && patternParts[1].length) || 0;if(!(options.round < 0)){value = dojo.number.round(value, maxPlaces, options.round);}var valueParts = String(Math.abs(value)).split(".");var fractional = valueParts[1] || "";if(options.places){valueParts[1] = dojo.string.pad(fractional.substr(0, options.places), options.places, '0', true);}else if(patternParts[1] && options.places !== 0){// Pad fractional with trailing zerosvar pad = patternParts[1].lastIndexOf("0") + 1;if(pad > fractional.length){valueParts[1] = dojo.string.pad(fractional, pad, '0', true);}// Truncate fractionalvar places = patternParts[1].length;if(places < fractional.length){valueParts[1] = fractional.substr(0, places);}}else{if(valueParts[1]){ valueParts.pop(); }}// Pad whole with leading zerosvar patternDigits = patternParts[0].replace(',', '');pad = patternDigits.indexOf("0");if(pad != -1){pad = patternDigits.length - pad;if(pad > valueParts[0].length){valueParts[0] = dojo.string.pad(valueParts[0], pad);}// Truncate wholeif(patternDigits.indexOf("#") == -1){valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);}}// Add group separatorsvar index = patternParts[0].lastIndexOf(',');var 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 || ".");};/*=====dojo.number.__regexpOptions = function(kwArgs){// pattern: String?// override pattern with this string. Default is provided based on// locale.// type: String?// choose a format type based on the locale from the following:// decimal, scientific, percent, currency. decimal by default.// locale: String?// override the locale used to determine formatting rules// strict: Boolean?// strict parsing, false by default// places: Number|String?// number of decimal places to accept: Infinity, a positive number, or// a range "n,m". By default, defined by pattern.}=====*/dojo.number.regexp = function(/*dojo.number.__regexpOptions?*/options){// summary:// Builds the regular needed to parse a number// description:// Returns regular expression with positive and negative match, group// and decimal separatorsreturn dojo.number._parseInfo(options).regexp; // String}dojo.number._parseInfo = function(/*Object?*/options){options = options || {};var locale = dojo.i18n.normalizeLocale(options.locale);var bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];//TODO: memoize?var group = bundle.group;var decimal = bundle.decimal;var 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 escapesvar patternList = pattern.split(';');if(patternList.length == 1){patternList.push("-" + patternList[0]);}var re = dojo.regexp.buildGroupRE(patternList, function(pattern){pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";return pattern.replace(dojo.number._numberPatternRE, function(format){var flags = {signed: false,separator: options.strict ? group : [group,""],fractional: options.fractional,decimal: decimal,exponent: false};var parts = format.split('.');var places = options.places;if(parts.length == 1 || places === 0){flags.fractional = false;}else{if(typeof places == "undefined"){ places = parts[1].lastIndexOf('0')+1; }if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specifiedif(!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 "("+dojo.number._realNumberRegexp(flags)+")";});}, true);if(isCurrency){// substitute the currency symbol for the placeholder in the patternre = re.replace(/(\s*)(\u00a4{1,3})(\s*)/g, function(match, before, target, after){var prop = ["symbol", "currency", "displayName"][target.length-1];var symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");before = before ? "\\s" : "";after = after ? "\\s" : "";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 returnreturn {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object}/*=====dojo.number.__parseOptions = function(kwArgs){// pattern: String// override pattern with this string. Default is provided based on// locale.// type: String?// choose a format type based on the locale from the following:// decimal, scientific, percent, currency. decimal by default.// locale: String// override the locale used to determine formatting rules// strict: Boolean?// strict parsing, false by default// currency: Object// object with currency information}=====*/dojo.number.parse = function(/*String*/expression, /*dojo.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.// Formatting patterns are implemented using the syntax described at// *URL*// expression:// A string representation of a Numbervar info = dojo.number._parseInfo(options);var results = (new RegExp("^"+info.regexp+"$")).exec(expression);if(!results){return NaN; //NaN}var absoluteMatch = results[1]; // match for the positive expressionif(!results[1]){if(!results[2]){return NaN; //NaN}// matched the negative patternabsoluteMatch =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 whitespaceabsoluteMatch = absoluteMatch.replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").replace(info.decimal, ".");// Adjust for negative sign, percent, etc. as necessaryreturn Number(absoluteMatch) * info.factor; //Number};/*=====dojo.number.__realNumberRegexpFlags = function(kwArgs){// 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 allowed. Can be true, false, or [true,// false]. Default is [true, false]// 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.}=====*/dojo.number._realNumberRegexp = function(/*dojo.number.__realNumberRegexpFlags?*/flags){// summary:// Builds a regular expression to match a real number in exponential// notation// flags:// An object// assign default values to missing paramtersflags = flags || {};if(typeof flags.places == "undefined"){ flags.places = Infinity; }if(typeof flags.decimal != "string"){ flags.decimal = "."; }if(typeof flags.fractional == "undefined" || /^0/.test(flags.places)){ flags.fractional = [true, false]; }if(typeof flags.exponent == "undefined"){ flags.exponent = [true, false]; }if(typeof flags.eSigned == "undefined"){ flags.eSigned = [true, false]; }// integer REvar integerRE = dojo.number._integerRegexp(flags);// decimal REvar decimalRE = dojo.regexp.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);// exponent REvar exponentRE = dojo.regexp.buildGroupRE(flags.exponent,function(q){if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }return "";});// real number REvar realRE = integerRE + decimalRE;// allow for decimals without integers, e.g. .25if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}return realRE + exponentRE; // String};/*=====dojo.number.__integerRegexpFlags = function(kwArgs){// 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// flags.groupSize2: Number?// second grouping (for India)}=====*/dojo.number._integerRegexp = function(/*dojo.number.__integerRegexpFlags?*/flags){// summary:// Builds a regular expression that matches an integer// flags:// An object// assign default values to missing paramtersflags = flags || {};if(typeof flags.signed == "undefined"){ flags.signed = [true, false]; }if(typeof flags.separator == "undefined"){flags.separator = "";}else if(typeof flags.groupSize == "undefined"){flags.groupSize = 3;}// build sign REvar signRE = dojo.regexp.buildGroupRE(flags.signed,function(q) { return q ? "[-+]" : ""; },true);// number REvar numberRE = dojo.regexp.buildGroupRE(flags.separator,function(sep){if(!sep){return "(?:0|[1-9]\\d*)";}sep = dojo.regexp.escapeString(sep);if(sep == " "){ sep = "\\s"; }else if(sep == "\xa0"){ sep = "\\s\\xa0"; }var grp = flags.groupSize, grp2 = flags.groupSize2;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);// integer REreturn signRE + numberRE; // String}}