dojo/number.js

  • Provides:

    • dojo.number
  • dojo.number

    • type
      Object
    • summary
      localized formatting and parsing routines for Number
  • dojo.number.__FormatOptions

    • type
      Function
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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;
    • summary
  • dojo.number.__FormatOptions.pattern

    • type
      String?
    • summary
      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.
  • dojo.number.__FormatOptions.type

    • type
      String?
    • summary
      choose a format type based on the locale from the following:
      decimal, scientific (not yet supported), percent, currency. decimal by default.
  • dojo.number.__FormatOptions.places

    • type
      Number?
    • summary
      fixed number of decimal places to show.  This overrides any
      information in the provided pattern.
  • dojo.number.__FormatOptions.round

    • type
      Number?
    • summary
      5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
      means do not round.
  • dojo.number.__FormatOptions.locale

    • type
      String?
    • summary
      override the locale used to determine formatting rules
  • dojo.number.__FormatOptions.fractional

    • type
      Boolean?
    • summary
      If false, show no decimal places, overriding places and pattern settings.
  • dojo.number.format

    • type
      Function
    • parameters:
      • value: (typeof Number)
        the number to be formatted
      • options: (typeof dojo.number.__FormatOptions)
    • source: [view]
       options = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
    • 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.
    • returns
      null|String
  • dojo.number._applyPattern

    • type
      Function
    • parameters:
      • value: (typeof Number)
        the number to be formatted.
      • pattern: (typeof String)
        a pattern string as described by
        [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
      • options: (typeof dojo.number.__FormatOptions)
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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}));
    • summary
      Apply pattern to format value as a string using options. Gives no
      consideration to local customs.
    • returns
      null|String
  • dojo.number.round

    • type
      Function
    • parameters:
      • value: (typeof Number)
        The number to round
      • places: (typeof Number)
        The number of decimal places where rounding takes place.  Defaults to 0 for whole rounding.
        Must be non-negative.
      • increment: (typeof Number)
        Rounds next place to nearest value of increment/10.  10 by default.
      • v: (typeof )
      • p: (typeof )
      • m: (typeof )
    • source: [view]
         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);
    • 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.
    • returns
      Number
    • 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
  • dojo.number.__FormatAbsoluteOptions

    • type
      Function
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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;
    • summary
  • dojo.number.__FormatAbsoluteOptions.decimal

    • type
      String?
    • summary
      the decimal separator
  • dojo.number.__FormatAbsoluteOptions.group

    • type
      String?
    • summary
      the group separator
  • dojo.number.__FormatAbsoluteOptions.places

    • type
      Number?|String?
    • summary
      number of decimal places.  the range &quot;n,m&quot; will format to m places.
  • dojo.number.__FormatAbsoluteOptions.round

    • type
      Number?
    • summary
      5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
      means don't round.
  • dojo.number._formatAbsolute

    • type
      Function
    • parameters:
      • value: (typeof Number)
        the number to be formatted, ignores sign
      • pattern: (typeof String)
        the number portion of a pattern (e.g. `#,##0.00`)
      • options: (typeof dojo.number.__FormatAbsoluteOptions)
    • source: [view]
       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] = dojo.string.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] = dojo.string.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 || ".");
    • summary
      Apply numeric pattern to absolute value using options. Gives no
      consideration to local customs.
  • dojo.number.__RegexpOptions

    • type
      Function
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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] = dojo.string.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] = dojo.string.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;
    • summary
  • dojo.number.__RegexpOptions.pattern

    • type
      String?
    • summary
      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.
  • dojo.number.__RegexpOptions.type

    • type
      String?
    • summary
      choose a format type based on the locale from the following:
      decimal, scientific (not yet supported), percent, currency. decimal by default.
  • dojo.number.__RegexpOptions.locale

    • type
      String?
    • summary
      override the locale used to determine formatting rules
  • dojo.number.__RegexpOptions.strict

    • type
      Boolean?
    • summary
      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
  • dojo.number.__RegexpOptions.places

    • type
      Number|String?
    • summary
      number of decimal places to accept: Infinity, a positive number, or
      a range &quot;n,m&quot;.  Defined by pattern or Infinity if pattern not provided.
  • dojo.number.regexp

    • type
      Function
    • parameters:
      • options: (typeof dojo.number.__RegexpOptions)
    • source: [view]
       return dojo.number._parseInfo(options).regexp; // String
    • summary
      Builds the regular needed to parse a number
    • description
      Returns regular expression with positive and negative match, group
      and decimal separators
    • returns
      String
  • dojo.number._parseInfo

    • type
      Function
    • parameters:
      • options: (typeof Object)
    • source: [view]
       options = options || {};
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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 = 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
          },


          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 = dojo.regexp.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
    • returns
      Object
    • summary
  • dojo.number.__ParseOptions

    • type
      Function
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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] = dojo.string.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] = dojo.string.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 = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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 = 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
          },


          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 = dojo.regexp.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;
    • summary
  • dojo.number.__ParseOptions.pattern

    • type
      String?
    • summary
      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.
  • dojo.number.__ParseOptions.type

    • type
      String?
    • summary
      choose a format type based on the locale from the following:
      decimal, scientific (not yet supported), percent, currency. decimal by default.
  • dojo.number.__ParseOptions.locale

    • type
      String?
    • summary
      override the locale used to determine formatting rules
  • dojo.number.__ParseOptions.strict

    • type
      Boolean?
    • summary
      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
  • dojo.number.__ParseOptions.fractional

    • type
      Boolean?|Array?
    • summary
      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.
  • dojo.number.parse

    • type
      Function
    • parameters:
      • expression: (typeof String)
        A string representation of a Number
      • options: (typeof dojo.number.__ParseOptions)
    • source: [view]
       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
    • 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.
    • returns
      NaN|Number
  • dojo.number.__RealNumberRegexpFlags

    • type
      Function
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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] = dojo.string.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] = dojo.string.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 = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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 = 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
          },


          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 = dojo.regexp.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;
    • summary
  • dojo.number.__RealNumberRegexpFlags.places

    • type
      Number?
    • summary
      The integer number of decimal places or a range given as &quot;n,m&quot;.  If
      not given, the decimal part is optional and the number of places is
      unlimited.
  • dojo.number.__RealNumberRegexpFlags.decimal

    • type
      String?
    • summary
      A string for the character used as the decimal point.  Default
      is &quot;.&quot;.
  • dojo.number.__RealNumberRegexpFlags.fractional

    • type
      Boolean?|Array?
    • summary
      Whether decimal places are used.  Can be true, false, or [true,
      false].  Default is [true, false] which means optional.
  • dojo.number.__RealNumberRegexpFlags.exponent

    • type
      Boolean?|Array?
    • summary
      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).
  • dojo.number.__RealNumberRegexpFlags.eSigned

    • type
      Boolean?|Array?
    • summary
      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

    • type
      Function
    • parameters:
      • flags: (typeof dojo.number.__RealNumberRegexpFlags)
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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] = dojo.string.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] = dojo.string.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 = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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 = 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
          },


          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 = dojo.regexp.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 = 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
       );


       var exponentRE = dojo.regexp.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
    • returns
      null|String|Number|Object|NaN
    • summary
  • dojo.number.__IntegerRegexpFlags

    • type
      Function
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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] = dojo.string.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] = dojo.string.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 = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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 = 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
          },


          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 = dojo.regexp.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 = 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
       );


       var exponentRE = dojo.regexp.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;
    • summary
  • dojo.number.__IntegerRegexpFlags.signed

    • type
      Boolean?
    • summary
      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).
  • dojo.number.__IntegerRegexpFlags.separator

    • type
      String?
    • summary
      The character used as the thousands separator. Default is no
      separator. For more than one symbol use an array, e.g. `[&quot;,&quot;, &quot;&quot;]`,
      makes ',' optional.
  • dojo.number.__IntegerRegexpFlags.groupSize

    • type
      Number?
    • summary
      group size between separators
  • dojo.number.__IntegerRegexpFlags.groupSize2

    • type
      Number?
    • summary
      second grouping, where separators 2..n have a different interval than the first separator (for India)
  • dojo.number._integerRegexp

    • type
      Function
    • parameters:
      • flags: (typeof dojo.number.__IntegerRegexpFlags)
    • source: [view]
      define("dojo/number", ["dojo", "dojo/i18n", "i18n!dojo/cldr/nls/number", "dojo/string", "dojo/regexp"], function(dojo) {
      dojo.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 = dojo.mixin({}, options || {});
       var locale = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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
       (function(){
        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] = dojo.string.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] = dojo.string.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 = dojo.i18n.normalizeLocale(options.locale),
        bundle = dojo.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 = 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
          },


          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 = dojo.regexp.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 = 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
       );


       var exponentRE = dojo.regexp.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 = dojo.regexp.buildGroupRE(flags.signed,
        function(q){ return q ? "[-+]" : ""; },
        true
       );


       var numberRE = dojo.regexp.buildGroupRE(flags.separator,
        function(sep){
         if(!sep){
          return "(?:\\d+)";
         }


         sep = dojo.regexp.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
    • returns
      null|String|Number|Object|NaN
    • summary
  • dojo.number._numberPatternRE

    • summary
  • dojo

    • type
      Object
    • summary