diff options
author | Andrew Dolgov <[email protected]> | 2011-03-04 19:02:28 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2011-03-04 19:02:59 +0300 |
commit | a089699c8915636ba4f158d77dba9b012bc93208 (patch) | |
tree | b2d7d051f1f55d44a6be07d3ee137e5a7ccfcefb /lib/dojo/number.js | |
parent | cfad9259a6feacfa8194b1312770ae6db1ecce50 (diff) |
build custom layer of Dojo to speed up loading of tt-rss (refs #293)
Diffstat (limited to 'lib/dojo/number.js')
-rw-r--r-- | lib/dojo/number.js | 849 |
1 files changed, 561 insertions, 288 deletions
diff --git a/lib/dojo/number.js b/lib/dojo/number.js index 95a2c5022..33aa6dd52 100644 --- a/lib/dojo/number.js +++ b/lib/dojo/number.js @@ -5,307 +5,580 @@ */ -if(!dojo._hasResource["dojo.number"]){ -dojo._hasResource["dojo.number"]=true; +if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojo.number"] = true; dojo.provide("dojo.number"); + dojo.require("dojo.i18n"); -dojo.requireLocalization("dojo.cldr","number",null,"ROOT,ar,ca,cs,da,de,el,en,en-au,en-gb,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ru,sk,sl,sv,th,tr,zh"); +dojo.requireLocalization("dojo.cldr", "number", null, "ROOT,ar,ca,cs,da,de,el,en,en-au,en-gb,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ru,sk,sl,sv,th,tr,zh"); dojo.require("dojo.string"); dojo.require("dojo.regexp"); -dojo.number.format=function(_1,_2){ -_2=dojo.mixin({},_2||{}); -var _3=dojo.i18n.normalizeLocale(_2.locale),_4=dojo.i18n.getLocalization("dojo.cldr","number",_3); -_2.customs=_4; -var _5=_2.pattern||_4[(_2.type||"decimal")+"Format"]; -if(isNaN(_1)||Math.abs(_1)==Infinity){ -return null; -} -return dojo.number._applyPattern(_1,_5,_2); -}; -dojo.number._numberPatternRE=/[#0,]*[#0](?:\.0*#*)?/; -dojo.number._applyPattern=function(_6,_7,_8){ -_8=_8||{}; -var _9=_8.customs.group,_a=_8.customs.decimal,_b=_7.split(";"),_c=_b[0]; -_7=_b[(_6<0)?1:0]||("-"+_c); -if(_7.indexOf("%")!=-1){ -_6*=100; -}else{ -if(_7.indexOf("‰")!=-1){ -_6*=1000; -}else{ -if(_7.indexOf("¤")!=-1){ -_9=_8.customs.currencyGroup||_9; -_a=_8.customs.currencyDecimal||_a; -_7=_7.replace(/\u00a4{1,3}/,function(_d){ -var _e=["symbol","currency","displayName"][_d.length-1]; -return _8[_e]||_8.currency||""; -}); -}else{ -if(_7.indexOf("E")!=-1){ -throw new Error("exponential notation not supported"); -} -} -} -} -var _f=dojo.number._numberPatternRE; -var _10=_c.match(_f); -if(!_10){ -throw new Error("unable to find a number expression in pattern: "+_7); -} -if(_8.fractional===false){ -_8.places=0; -} -return _7.replace(_f,dojo.number._formatAbsolute(_6,_10[0],{decimal:_a,group:_9,places:_8.places,round:_8.round})); -}; -dojo.number.round=function(_11,_12,_13){ -var _14=10/(_13||10); -return (_14*+_11).toFixed(_12)/_14; -}; -if((0.9).toFixed()==0){ -(function(){ -var _15=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 _15(v,p,m)+(v>0?d:-d); -}; -})(); -} -dojo.number._formatAbsolute=function(_16,_17,_18){ -_18=_18||{}; -if(_18.places===true){ -_18.places=0; -} -if(_18.places===Infinity){ -_18.places=6; -} -var _19=_17.split("."),_1a=typeof _18.places=="string"&&_18.places.indexOf(","),_1b=_18.places; -if(_1a){ -_1b=_18.places.substring(_1a+1); -}else{ -if(!(_1b>=0)){ -_1b=(_19[1]||[]).length; -} -} -if(!(_18.round<0)){ -_16=dojo.number.round(_16,_1b,_18.round); -} -var _1c=String(Math.abs(_16)).split("."),_1d=_1c[1]||""; -if(_19[1]||_18.places){ -if(_1a){ -_18.places=_18.places.substring(0,_1a); -} -var pad=_18.places!==undefined?_18.places:(_19[1]&&_19[1].lastIndexOf("0")+1); -if(pad>_1d.length){ -_1c[1]=dojo.string.pad(_1d,pad,"0",true); -} -if(_1b<_1d.length){ -_1c[1]=_1d.substr(0,_1b); -} -}else{ -if(_1c[1]){ -_1c.pop(); -} -} -var _1e=_19[0].replace(",",""); -pad=_1e.indexOf("0"); -if(pad!=-1){ -pad=_1e.length-pad; -if(pad>_1c[0].length){ -_1c[0]=dojo.string.pad(_1c[0],pad); -} -if(_1e.indexOf("#")==-1){ -_1c[0]=_1c[0].substr(_1c[0].length-pad); -} -} -var _1f=_19[0].lastIndexOf(","),_20,_21; -if(_1f!=-1){ -_20=_19[0].length-_1f-1; -var _22=_19[0].substr(0,_1f); -_1f=_22.lastIndexOf(","); -if(_1f!=-1){ -_21=_22.length-_1f-1; -} -} -var _23=[]; -for(var _24=_1c[0];_24;){ -var off=_24.length-_20; -_23.push((off>0)?_24.substr(off):_24); -_24=(off>0)?_24.slice(0,off):""; -if(_21){ -_20=_21; -delete _21; -} + + +/*===== +dojo.number = { + // summary: localized formatting and parsing routines for Number } -_1c[0]=_23.reverse().join(_18.group||","); -return _1c.join(_18.decimal||"."); -}; -dojo.number.regexp=function(_25){ -return dojo.number._parseInfo(_25).regexp; + +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._parseInfo=function(_26){ -_26=_26||{}; -var _27=dojo.i18n.normalizeLocale(_26.locale),_28=dojo.i18n.getLocalization("dojo.cldr","number",_27),_29=_26.pattern||_28[(_26.type||"decimal")+"Format"],_2a=_28.group,_2b=_28.decimal,_2c=1; -if(_29.indexOf("%")!=-1){ -_2c/=100; -}else{ -if(_29.indexOf("‰")!=-1){ -_2c/=1000; -}else{ -var _2d=_29.indexOf("¤")!=-1; -if(_2d){ -_2a=_28.currencyGroup||_2a; -_2b=_28.currencyDecimal||_2b; -} -} -} -var _2e=_29.split(";"); -if(_2e.length==1){ -_2e.push("-"+_2e[0]); -} -var re=dojo.regexp.buildGroupRE(_2e,function(_2f){ -_2f="(?:"+dojo.regexp.escapeString(_2f,".")+")"; -return _2f.replace(dojo.number._numberPatternRE,function(_30){ -var _31={signed:false,separator:_26.strict?_2a:[_2a,""],fractional:_26.fractional,decimal:_2b,exponent:false},_32=_30.split("."),_33=_26.places; -if(_32.length==1&&_2c!=1){ -_32[1]="###"; -} -if(_32.length==1||_33===0){ -_31.fractional=false; -}else{ -if(_33===undefined){ -_33=_26.pattern?_32[1].lastIndexOf("0")+1:Infinity; -} -if(_33&&_26.fractional==undefined){ -_31.fractional=true; -} -if(!_26.places&&(_33<_32[1].length)){ -_33+=","+_32[1].length; -} -_31.places=_33; -} -var _34=_32[0].split(","); -if(_34.length>1){ -_31.groupSize=_34.pop().length; -if(_34.length>1){ -_31.groupSize2=_34.pop().length; -} -} -return "("+dojo.number._realNumberRegexp(_31)+")"; -}); -},true); -if(_2d){ -re=re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g,function(_35,_36,_37,_38){ -var _39=["symbol","currency","displayName"][_37.length-1],_3a=dojo.regexp.escapeString(_26[_39]||_26.currency||""); -_36=_36?"[\\s\\xa0]":""; -_38=_38?"[\\s\\xa0]":""; -if(!_26.strict){ -if(_36){ -_36+="*"; -} -if(_38){ -_38+="*"; + +//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})); } -return "(?:"+_36+_3a+_38+")?"; + +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 } -return _36+_3a+_38; -}); + +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); + } + })(); } -return {regexp:re.replace(/[\xa0 ]/g,"[\\s\\xa0]"),group:_2a,decimal:_2b,factor:_2c}; + +/*===== +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.parse=function(_3b,_3c){ -var _3d=dojo.number._parseInfo(_3c),_3e=(new RegExp("^"+_3d.regexp+"$")).exec(_3b); -if(!_3e){ -return NaN; -} -var _3f=_3e[1]; -if(!_3e[1]){ -if(!_3e[2]){ -return NaN; + +/*===== +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 } -_3f=_3e[2]; -_3d.factor*=-1; + +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 } -_3f=_3f.replace(new RegExp("["+_3d.group+"\\s\\xa0"+"]","g"),"").replace(_3d.decimal,"."); -return _3f*_3d.factor; + +/*===== +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._realNumberRegexp=function(_40){ -_40=_40||{}; -if(!("places" in _40)){ -_40.places=Infinity; -} -if(typeof _40.decimal!="string"){ -_40.decimal="."; -} -if(!("fractional" in _40)||/^0/.test(_40.places)){ -_40.fractional=[true,false]; -} -if(!("exponent" in _40)){ -_40.exponent=[true,false]; -} -if(!("eSigned" in _40)){ -_40.eSigned=[true,false]; -} -var _41=dojo.number._integerRegexp(_40),_42=dojo.regexp.buildGroupRE(_40.fractional,function(q){ -var re=""; -if(q&&(_40.places!==0)){ -re="\\"+_40.decimal; -if(_40.places==Infinity){ -re="(?:"+re+"\\d+)?"; -}else{ -re+="\\d{"+_40.places+"}"; -} -} -return re; -},true); -var _43=dojo.regexp.buildGroupRE(_40.exponent,function(q){ -if(q){ -return "([eE]"+dojo.number._integerRegexp({signed:_40.eSigned})+")"; -} -return ""; -}); -var _44=_41+_42; -if(_42){ -_44="(?:(?:"+_44+")|(?:"+_42+"))"; -} -return _44+_43; + +/*===== +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._integerRegexp=function(_45){ -_45=_45||{}; -if(!("signed" in _45)){ -_45.signed=[true,false]; -} -if(!("separator" in _45)){ -_45.separator=""; -}else{ -if(!("groupSize" in _45)){ -_45.groupSize=3; -} -} -var _46=dojo.regexp.buildGroupRE(_45.signed,function(q){ -return q?"[-+]":""; -},true); -var _47=dojo.regexp.buildGroupRE(_45.separator,function(sep){ -if(!sep){ -return "(?:\\d+)"; -} -sep=dojo.regexp.escapeString(sep); -if(sep==" "){ -sep="\\s"; -}else{ -if(sep==" "){ -sep="\\s\\xa0"; -} -} -var grp=_45.groupSize,_48=_45.groupSize2; -if(_48){ -var _49="(?:0|[1-9]\\d{0,"+(_48-1)+"}(?:["+sep+"]\\d{"+_48+"})*["+sep+"]\\d{"+grp+"})"; -return ((grp-_48)>0)?"(?:"+_49+"|(?:0|[1-9]\\d{0,"+(grp-1)+"}))":_49; + +/*===== +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 } -return "(?:0|[1-9]\\d{0,"+(grp-1)+"}(?:["+sep+"]\\d{"+grp+"})*)"; -},true); -return _46+_47; -}; + } |