]> git.wh0rd.org - tt-rss.git/blobdiff - lib/dojo/number.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / 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 (file)
index 0000000..c3635df
--- /dev/null
@@ -0,0 +1,576 @@
+define("dojo/number", ["./_base/kernel", "./_base/lang", "./i18n", "./i18n!./cldr/nls/number", "./string", "./regexp"],
+       function(dojo, lang, i18n, nlsNumber, dstring, dregexp) {
+
+       // module:
+       //              dojo/number
+       // summary:
+       //              TODOC
+
+lang.getObject("number", true, dojo);
+
+/*=====
+dojo.number = {
+       // summary: localized formatting and parsing routines for Number
+}
+
+dojo.number.__FormatOptions = function(){
+       //      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.
+       this.pattern = pattern;
+       this.type = type;
+       this.places = places;
+       this.round = round;
+       this.locale = locale;
+       this.fractional = fractional;
+}
+=====*/
+
+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
+       //              [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 dojo.number._applyPattern(value, pattern, options); // String
+};
+
+//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
+dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
+
+dojo.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 by
+       //              [unicode.org TR35](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 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 = dojo.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,
+               dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
+};
+
+dojo.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:
+       //              >>> dojo.number.round(-0.5)
+       //              -1
+       //              >>> dojo.number.round(162.295, 2)
+       //              162.29  // note floating point error.  Should be 162.3
+       //              >>> dojo.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 = dojo.number.round;
+       dojo.number.round = function(v, p, m){
+               var d = Math.pow(10, -p || 0), a = Math.abs(v);
+               if(!v || a >= d || a * Math.pow(10, p + 1) < 5){
+                       d = 0;
+               }
+               return round(v, p, m) + (v > 0 ? d : -d);
+       };
+}
+
+/*=====
+dojo.number.__FormatAbsoluteOptions = function(){
+       //      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.
+       this.decimal = decimal;
+       this.group = group;
+       this.places = places;
+       this.round = 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 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 = dojo.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 || ".");
+};
+
+/*=====
+dojo.number.__RegexpOptions = function(){
+       //      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.
+       this.pattern = pattern;
+       this.type = type;
+       this.locale = locale;
+       this.strict = strict;
+       this.places = places;
+}
+=====*/
+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 separators
+       return dojo.number._parseInfo(options).regexp; // String
+};
+
+dojo.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(dojo.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 "("+dojo.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
+};
+
+/*=====
+dojo.number.__ParseOptions = function(){
+       //      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.
+       this.pattern = pattern;
+       this.type = type;
+       this.locale = locale;
+       this.strict = strict;
+       this.fractional = fractional;
+}
+=====*/
+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
+       //              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 = dojo.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
+};
+
+/*=====
+dojo.number.__RealNumberRegexpFlags = function(){
+       //      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.
+       this.places = places;
+       this.decimal = decimal;
+       this.fractional = fractional;
+       this.exponent = exponent;
+       this.eSigned = eSigned;
+}
+=====*/
+
+dojo.number._realNumberRegexp = function(/*dojo.number.__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 = dojo.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]" + dojo.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
+};
+
+/*=====
+dojo.number.__IntegerRegexpFlags = function(){
+       //      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)
+       this.signed = signed;
+       this.separator = separator;
+       this.groupSize = groupSize;
+       this.groupSize2 = groupSize2;
+}
+=====*/
+
+dojo.number._integerRegexp = function(/*dojo.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 dojo.number;
+});