]>
Commit | Line | Data |
---|---|---|
1354d172 AD |
1 | define("dojo/number", ["./_base/kernel", "./_base/lang", "./i18n", "./i18n!./cldr/nls/number", "./string", "./regexp"], |
2 | function(dojo, lang, i18n, nlsNumber, dstring, dregexp) { | |
3 | ||
4 | // module: | |
5 | // dojo/number | |
6 | // summary: | |
7 | // TODOC | |
8 | ||
9 | lang.getObject("number", true, dojo); | |
10 | ||
11 | /*===== | |
12 | dojo.number = { | |
13 | // summary: localized formatting and parsing routines for Number | |
14 | } | |
15 | ||
16 | dojo.number.__FormatOptions = function(){ | |
17 | // pattern: String? | |
18 | // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns) | |
19 | // with this string. Default value is based on locale. Overriding this property will defeat | |
20 | // localization. Literal characters in patterns are not supported. | |
21 | // type: String? | |
22 | // choose a format type based on the locale from the following: | |
23 | // decimal, scientific (not yet supported), percent, currency. decimal by default. | |
24 | // places: Number? | |
25 | // fixed number of decimal places to show. This overrides any | |
26 | // information in the provided pattern. | |
27 | // round: Number? | |
28 | // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1 | |
29 | // means do not round. | |
30 | // locale: String? | |
31 | // override the locale used to determine formatting rules | |
32 | // fractional: Boolean? | |
33 | // If false, show no decimal places, overriding places and pattern settings. | |
34 | this.pattern = pattern; | |
35 | this.type = type; | |
36 | this.places = places; | |
37 | this.round = round; | |
38 | this.locale = locale; | |
39 | this.fractional = fractional; | |
40 | } | |
41 | =====*/ | |
42 | ||
43 | dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){ | |
44 | // summary: | |
45 | // Format a Number as a String, using locale-specific settings | |
46 | // description: | |
47 | // Create a string from a Number using a known localized pattern. | |
48 | // Formatting patterns appropriate to the locale are chosen from the | |
49 | // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and | |
50 | // delimiters. | |
51 | // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null. | |
52 | // value: | |
53 | // the number to be formatted | |
54 | ||
55 | options = lang.mixin({}, options || {}); | |
56 | var locale = i18n.normalizeLocale(options.locale), | |
57 | bundle = i18n.getLocalization("dojo.cldr", "number", locale); | |
58 | options.customs = bundle; | |
59 | var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"]; | |
60 | if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null | |
61 | return dojo.number._applyPattern(value, pattern, options); // String | |
62 | }; | |
63 | ||
64 | //dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough | |
65 | dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough | |
66 | ||
67 | dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){ | |
68 | // summary: | |
69 | // Apply pattern to format value as a string using options. Gives no | |
70 | // consideration to local customs. | |
71 | // value: | |
72 | // the number to be formatted. | |
73 | // pattern: | |
74 | // a pattern string as described by | |
75 | // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns) | |
76 | // options: dojo.number.__FormatOptions? | |
77 | // _applyPattern is usually called via `dojo.number.format()` which | |
78 | // populates an extra property in the options parameter, "customs". | |
79 | // The customs object specifies group and decimal parameters if set. | |
80 | ||
81 | //TODO: support escapes | |
82 | options = options || {}; | |
83 | var group = options.customs.group, | |
84 | decimal = options.customs.decimal, | |
85 | patternList = pattern.split(';'), | |
86 | positivePattern = patternList[0]; | |
87 | pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern); | |
88 | ||
89 | //TODO: only test against unescaped | |
90 | if(pattern.indexOf('%') != -1){ | |
91 | value *= 100; | |
92 | }else if(pattern.indexOf('\u2030') != -1){ | |
93 | value *= 1000; // per mille | |
94 | }else if(pattern.indexOf('\u00a4') != -1){ | |
95 | group = options.customs.currencyGroup || group;//mixins instead? | |
96 | decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead? | |
97 | pattern = pattern.replace(/\u00a4{1,3}/, function(match){ | |
98 | var prop = ["symbol", "currency", "displayName"][match.length-1]; | |
99 | return options[prop] || options.currency || ""; | |
100 | }); | |
101 | }else if(pattern.indexOf('E') != -1){ | |
102 | throw new Error("exponential notation not supported"); | |
103 | } | |
104 | ||
105 | //TODO: support @ sig figs? | |
106 | var numberPatternRE = dojo.number._numberPatternRE; | |
107 | var numberPattern = positivePattern.match(numberPatternRE); | |
108 | if(!numberPattern){ | |
109 | throw new Error("unable to find a number expression in pattern: "+pattern); | |
110 | } | |
111 | if(options.fractional === false){ options.places = 0; } | |
112 | return pattern.replace(numberPatternRE, | |
113 | dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round})); | |
114 | }; | |
115 | ||
116 | dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){ | |
117 | // summary: | |
118 | // Rounds to the nearest value with the given number of decimal places, away from zero | |
119 | // description: | |
120 | // Rounds to the nearest value with the given number of decimal places, away from zero if equal. | |
121 | // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by | |
122 | // fractional increments also, such as the nearest quarter. | |
123 | // NOTE: Subject to floating point errors. See dojox.math.round for experimental workaround. | |
124 | // value: | |
125 | // The number to round | |
126 | // places: | |
127 | // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding. | |
128 | // Must be non-negative. | |
129 | // increment: | |
130 | // Rounds next place to nearest value of increment/10. 10 by default. | |
131 | // example: | |
132 | // >>> dojo.number.round(-0.5) | |
133 | // -1 | |
134 | // >>> dojo.number.round(162.295, 2) | |
135 | // 162.29 // note floating point error. Should be 162.3 | |
136 | // >>> dojo.number.round(10.71, 0, 2.5) | |
137 | // 10.75 | |
138 | var factor = 10 / (increment || 10); | |
139 | return (factor * +value).toFixed(places) / factor; // Number | |
140 | }; | |
141 | ||
142 | if((0.9).toFixed() == 0){ | |
143 | // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit | |
144 | // is just after the rounding place and is >=5 | |
145 | var round = dojo.number.round; | |
146 | dojo.number.round = function(v, p, m){ | |
147 | var d = Math.pow(10, -p || 0), a = Math.abs(v); | |
148 | if(!v || a >= d || a * Math.pow(10, p + 1) < 5){ | |
149 | d = 0; | |
150 | } | |
151 | return round(v, p, m) + (v > 0 ? d : -d); | |
152 | }; | |
153 | } | |
154 | ||
155 | /*===== | |
156 | dojo.number.__FormatAbsoluteOptions = function(){ | |
157 | // decimal: String? | |
158 | // the decimal separator | |
159 | // group: String? | |
160 | // the group separator | |
161 | // places: Number?|String? | |
162 | // number of decimal places. the range "n,m" will format to m places. | |
163 | // round: Number? | |
164 | // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1 | |
165 | // means don't round. | |
166 | this.decimal = decimal; | |
167 | this.group = group; | |
168 | this.places = places; | |
169 | this.round = round; | |
170 | } | |
171 | =====*/ | |
172 | ||
173 | dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){ | |
174 | // summary: | |
175 | // Apply numeric pattern to absolute value using options. Gives no | |
176 | // consideration to local customs. | |
177 | // value: | |
178 | // the number to be formatted, ignores sign | |
179 | // pattern: | |
180 | // the number portion of a pattern (e.g. `#,##0.00`) | |
181 | options = options || {}; | |
182 | if(options.places === true){options.places=0;} | |
183 | if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit | |
184 | ||
185 | var patternParts = pattern.split("."), | |
186 | comma = typeof options.places == "string" && options.places.indexOf(","), | |
187 | maxPlaces = options.places; | |
188 | if(comma){ | |
189 | maxPlaces = options.places.substring(comma + 1); | |
190 | }else if(!(maxPlaces >= 0)){ | |
191 | maxPlaces = (patternParts[1] || []).length; | |
192 | } | |
193 | if(!(options.round < 0)){ | |
194 | value = dojo.number.round(value, maxPlaces, options.round); | |
195 | } | |
196 | ||
197 | var valueParts = String(Math.abs(value)).split("."), | |
198 | fractional = valueParts[1] || ""; | |
199 | if(patternParts[1] || options.places){ | |
200 | if(comma){ | |
201 | options.places = options.places.substring(0, comma); | |
202 | } | |
203 | // Pad fractional with trailing zeros | |
204 | var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1); | |
205 | if(pad > fractional.length){ | |
206 | valueParts[1] = dstring.pad(fractional, pad, '0', true); | |
207 | } | |
208 | ||
209 | // Truncate fractional | |
210 | if(maxPlaces < fractional.length){ | |
211 | valueParts[1] = fractional.substr(0, maxPlaces); | |
212 | } | |
213 | }else{ | |
214 | if(valueParts[1]){ valueParts.pop(); } | |
215 | } | |
216 | ||
217 | // Pad whole with leading zeros | |
218 | var patternDigits = patternParts[0].replace(',', ''); | |
219 | pad = patternDigits.indexOf("0"); | |
220 | if(pad != -1){ | |
221 | pad = patternDigits.length - pad; | |
222 | if(pad > valueParts[0].length){ | |
223 | valueParts[0] = dstring.pad(valueParts[0], pad); | |
224 | } | |
225 | ||
226 | // Truncate whole | |
227 | if(patternDigits.indexOf("#") == -1){ | |
228 | valueParts[0] = valueParts[0].substr(valueParts[0].length - pad); | |
229 | } | |
230 | } | |
231 | ||
232 | // Add group separators | |
233 | var index = patternParts[0].lastIndexOf(','), | |
234 | groupSize, groupSize2; | |
235 | if(index != -1){ | |
236 | groupSize = patternParts[0].length - index - 1; | |
237 | var remainder = patternParts[0].substr(0, index); | |
238 | index = remainder.lastIndexOf(','); | |
239 | if(index != -1){ | |
240 | groupSize2 = remainder.length - index - 1; | |
241 | } | |
242 | } | |
243 | var pieces = []; | |
244 | for(var whole = valueParts[0]; whole;){ | |
245 | var off = whole.length - groupSize; | |
246 | pieces.push((off > 0) ? whole.substr(off) : whole); | |
247 | whole = (off > 0) ? whole.slice(0, off) : ""; | |
248 | if(groupSize2){ | |
249 | groupSize = groupSize2; | |
250 | delete groupSize2; | |
251 | } | |
252 | } | |
253 | valueParts[0] = pieces.reverse().join(options.group || ","); | |
254 | ||
255 | return valueParts.join(options.decimal || "."); | |
256 | }; | |
257 | ||
258 | /*===== | |
259 | dojo.number.__RegexpOptions = function(){ | |
260 | // pattern: String? | |
261 | // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns) | |
262 | // with this string. Default value is based on locale. Overriding this property will defeat | |
263 | // localization. | |
264 | // type: String? | |
265 | // choose a format type based on the locale from the following: | |
266 | // decimal, scientific (not yet supported), percent, currency. decimal by default. | |
267 | // locale: String? | |
268 | // override the locale used to determine formatting rules | |
269 | // strict: Boolean? | |
270 | // strict parsing, false by default. Strict parsing requires input as produced by the format() method. | |
271 | // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators | |
272 | // places: Number|String? | |
273 | // number of decimal places to accept: Infinity, a positive number, or | |
274 | // a range "n,m". Defined by pattern or Infinity if pattern not provided. | |
275 | this.pattern = pattern; | |
276 | this.type = type; | |
277 | this.locale = locale; | |
278 | this.strict = strict; | |
279 | this.places = places; | |
280 | } | |
281 | =====*/ | |
282 | dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){ | |
283 | // summary: | |
284 | // Builds the regular needed to parse a number | |
285 | // description: | |
286 | // Returns regular expression with positive and negative match, group | |
287 | // and decimal separators | |
288 | return dojo.number._parseInfo(options).regexp; // String | |
289 | }; | |
290 | ||
291 | dojo.number._parseInfo = function(/*Object?*/options){ | |
292 | options = options || {}; | |
293 | var locale = i18n.normalizeLocale(options.locale), | |
294 | bundle = i18n.getLocalization("dojo.cldr", "number", locale), | |
295 | pattern = options.pattern || bundle[(options.type || "decimal") + "Format"], | |
296 | //TODO: memoize? | |
297 | group = bundle.group, | |
298 | decimal = bundle.decimal, | |
299 | factor = 1; | |
300 | ||
301 | if(pattern.indexOf('%') != -1){ | |
302 | factor /= 100; | |
303 | }else if(pattern.indexOf('\u2030') != -1){ | |
304 | factor /= 1000; // per mille | |
305 | }else{ | |
306 | var isCurrency = pattern.indexOf('\u00a4') != -1; | |
307 | if(isCurrency){ | |
308 | group = bundle.currencyGroup || group; | |
309 | decimal = bundle.currencyDecimal || decimal; | |
310 | } | |
311 | } | |
312 | ||
313 | //TODO: handle quoted escapes | |
314 | var patternList = pattern.split(';'); | |
315 | if(patternList.length == 1){ | |
316 | patternList.push("-" + patternList[0]); | |
317 | } | |
318 | ||
319 | var re = dregexp.buildGroupRE(patternList, function(pattern){ | |
320 | pattern = "(?:"+dregexp.escapeString(pattern, '.')+")"; | |
321 | return pattern.replace(dojo.number._numberPatternRE, function(format){ | |
322 | var flags = { | |
323 | signed: false, | |
324 | separator: options.strict ? group : [group,""], | |
325 | fractional: options.fractional, | |
326 | decimal: decimal, | |
327 | exponent: false | |
328 | }, | |
329 | ||
330 | parts = format.split('.'), | |
331 | places = options.places; | |
332 | ||
333 | // special condition for percent (factor != 1) | |
334 | // allow decimal places even if not specified in pattern | |
335 | if(parts.length == 1 && factor != 1){ | |
336 | parts[1] = "###"; | |
337 | } | |
338 | if(parts.length == 1 || places === 0){ | |
339 | flags.fractional = false; | |
340 | }else{ | |
341 | if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; } | |
342 | if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified | |
343 | if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; } | |
344 | flags.places = places; | |
345 | } | |
346 | var groups = parts[0].split(','); | |
347 | if(groups.length > 1){ | |
348 | flags.groupSize = groups.pop().length; | |
349 | if(groups.length > 1){ | |
350 | flags.groupSize2 = groups.pop().length; | |
351 | } | |
352 | } | |
353 | return "("+dojo.number._realNumberRegexp(flags)+")"; | |
354 | }); | |
355 | }, true); | |
356 | ||
357 | if(isCurrency){ | |
358 | // substitute the currency symbol for the placeholder in the pattern | |
359 | re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){ | |
360 | var prop = ["symbol", "currency", "displayName"][target.length-1], | |
361 | symbol = dregexp.escapeString(options[prop] || options.currency || ""); | |
362 | before = before ? "[\\s\\xa0]" : ""; | |
363 | after = after ? "[\\s\\xa0]" : ""; | |
364 | if(!options.strict){ | |
365 | if(before){before += "*";} | |
366 | if(after){after += "*";} | |
367 | return "(?:"+before+symbol+after+")?"; | |
368 | } | |
369 | return before+symbol+after; | |
370 | }); | |
371 | } | |
372 | ||
373 | //TODO: substitute localized sign/percent/permille/etc.? | |
374 | ||
375 | // normalize whitespace and return | |
376 | return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object | |
377 | }; | |
378 | ||
379 | /*===== | |
380 | dojo.number.__ParseOptions = function(){ | |
381 | // pattern: String? | |
382 | // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns) | |
383 | // with this string. Default value is based on locale. Overriding this property will defeat | |
384 | // localization. Literal characters in patterns are not supported. | |
385 | // type: String? | |
386 | // choose a format type based on the locale from the following: | |
387 | // decimal, scientific (not yet supported), percent, currency. decimal by default. | |
388 | // locale: String? | |
389 | // override the locale used to determine formatting rules | |
390 | // strict: Boolean? | |
391 | // strict parsing, false by default. Strict parsing requires input as produced by the format() method. | |
392 | // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators | |
393 | // fractional: Boolean?|Array? | |
394 | // Whether to include the fractional portion, where the number of decimal places are implied by pattern | |
395 | // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional. | |
396 | this.pattern = pattern; | |
397 | this.type = type; | |
398 | this.locale = locale; | |
399 | this.strict = strict; | |
400 | this.fractional = fractional; | |
401 | } | |
402 | =====*/ | |
403 | dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){ | |
404 | // summary: | |
405 | // Convert a properly formatted string to a primitive Number, using | |
406 | // locale-specific settings. | |
407 | // description: | |
408 | // Create a Number from a string using a known localized pattern. | |
409 | // Formatting patterns are chosen appropriate to the locale | |
410 | // and follow the syntax described by | |
411 | // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns) | |
412 | // Note that literal characters in patterns are not supported. | |
413 | // expression: | |
414 | // A string representation of a Number | |
415 | var info = dojo.number._parseInfo(options), | |
416 | results = (new RegExp("^"+info.regexp+"$")).exec(expression); | |
417 | if(!results){ | |
418 | return NaN; //NaN | |
419 | } | |
420 | var absoluteMatch = results[1]; // match for the positive expression | |
421 | if(!results[1]){ | |
422 | if(!results[2]){ | |
423 | return NaN; //NaN | |
424 | } | |
425 | // matched the negative pattern | |
426 | absoluteMatch =results[2]; | |
427 | info.factor *= -1; | |
428 | } | |
429 | ||
430 | // Transform it to something Javascript can parse as a number. Normalize | |
431 | // decimal point and strip out group separators or alternate forms of whitespace | |
432 | absoluteMatch = absoluteMatch. | |
433 | replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), ""). | |
434 | replace(info.decimal, "."); | |
435 | // Adjust for negative sign, percent, etc. as necessary | |
436 | return absoluteMatch * info.factor; //Number | |
437 | }; | |
438 | ||
439 | /*===== | |
440 | dojo.number.__RealNumberRegexpFlags = function(){ | |
441 | // places: Number? | |
442 | // The integer number of decimal places or a range given as "n,m". If | |
443 | // not given, the decimal part is optional and the number of places is | |
444 | // unlimited. | |
445 | // decimal: String? | |
446 | // A string for the character used as the decimal point. Default | |
447 | // is ".". | |
448 | // fractional: Boolean?|Array? | |
449 | // Whether decimal places are used. Can be true, false, or [true, | |
450 | // false]. Default is [true, false] which means optional. | |
451 | // exponent: Boolean?|Array? | |
452 | // Express in exponential notation. Can be true, false, or [true, | |
453 | // false]. Default is [true, false], (i.e. will match if the | |
454 | // exponential part is present are not). | |
455 | // eSigned: Boolean?|Array? | |
456 | // The leading plus-or-minus sign on the exponent. Can be true, | |
457 | // false, or [true, false]. Default is [true, false], (i.e. will | |
458 | // match if it is signed or unsigned). flags in regexp.integer can be | |
459 | // applied. | |
460 | this.places = places; | |
461 | this.decimal = decimal; | |
462 | this.fractional = fractional; | |
463 | this.exponent = exponent; | |
464 | this.eSigned = eSigned; | |
465 | } | |
466 | =====*/ | |
467 | ||
468 | dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){ | |
469 | // summary: | |
470 | // Builds a regular expression to match a real number in exponential | |
471 | // notation | |
472 | ||
473 | // assign default values to missing parameters | |
474 | flags = flags || {}; | |
475 | //TODO: use mixin instead? | |
476 | if(!("places" in flags)){ flags.places = Infinity; } | |
477 | if(typeof flags.decimal != "string"){ flags.decimal = "."; } | |
478 | if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; } | |
479 | if(!("exponent" in flags)){ flags.exponent = [true, false]; } | |
480 | if(!("eSigned" in flags)){ flags.eSigned = [true, false]; } | |
481 | ||
482 | var integerRE = dojo.number._integerRegexp(flags), | |
483 | decimalRE = dregexp.buildGroupRE(flags.fractional, | |
484 | function(q){ | |
485 | var re = ""; | |
486 | if(q && (flags.places!==0)){ | |
487 | re = "\\" + flags.decimal; | |
488 | if(flags.places == Infinity){ | |
489 | re = "(?:" + re + "\\d+)?"; | |
490 | }else{ | |
491 | re += "\\d{" + flags.places + "}"; | |
492 | } | |
493 | } | |
494 | return re; | |
495 | }, | |
496 | true | |
497 | ); | |
498 | ||
499 | var exponentRE = dregexp.buildGroupRE(flags.exponent, | |
500 | function(q){ | |
501 | if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; } | |
502 | return ""; | |
503 | } | |
504 | ); | |
505 | ||
506 | var realRE = integerRE + decimalRE; | |
507 | // allow for decimals without integers, e.g. .25 | |
508 | if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";} | |
509 | return realRE + exponentRE; // String | |
510 | }; | |
511 | ||
512 | /*===== | |
513 | dojo.number.__IntegerRegexpFlags = function(){ | |
514 | // signed: Boolean? | |
515 | // The leading plus-or-minus sign. Can be true, false, or `[true,false]`. | |
516 | // Default is `[true, false]`, (i.e. will match if it is signed | |
517 | // or unsigned). | |
518 | // separator: String? | |
519 | // The character used as the thousands separator. Default is no | |
520 | // separator. For more than one symbol use an array, e.g. `[",", ""]`, | |
521 | // makes ',' optional. | |
522 | // groupSize: Number? | |
523 | // group size between separators | |
524 | // groupSize2: Number? | |
525 | // second grouping, where separators 2..n have a different interval than the first separator (for India) | |
526 | this.signed = signed; | |
527 | this.separator = separator; | |
528 | this.groupSize = groupSize; | |
529 | this.groupSize2 = groupSize2; | |
530 | } | |
531 | =====*/ | |
532 | ||
533 | dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){ | |
534 | // summary: | |
535 | // Builds a regular expression that matches an integer | |
536 | ||
537 | // assign default values to missing parameters | |
538 | flags = flags || {}; | |
539 | if(!("signed" in flags)){ flags.signed = [true, false]; } | |
540 | if(!("separator" in flags)){ | |
541 | flags.separator = ""; | |
542 | }else if(!("groupSize" in flags)){ | |
543 | flags.groupSize = 3; | |
544 | } | |
545 | ||
546 | var signRE = dregexp.buildGroupRE(flags.signed, | |
547 | function(q){ return q ? "[-+]" : ""; }, | |
548 | true | |
549 | ); | |
550 | ||
551 | var numberRE = dregexp.buildGroupRE(flags.separator, | |
552 | function(sep){ | |
553 | if(!sep){ | |
554 | return "(?:\\d+)"; | |
555 | } | |
556 | ||
557 | sep = dregexp.escapeString(sep); | |
558 | if(sep == " "){ sep = "\\s"; } | |
559 | else if(sep == "\xa0"){ sep = "\\s\\xa0"; } | |
560 | ||
561 | var grp = flags.groupSize, grp2 = flags.groupSize2; | |
562 | //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933 | |
563 | if(grp2){ | |
564 | var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})"; | |
565 | return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE; | |
566 | } | |
567 | return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)"; | |
568 | }, | |
569 | true | |
570 | ); | |
571 | ||
572 | return signRE + numberRE; // String | |
573 | }; | |
574 | ||
575 | return dojo.number; | |
576 | }); |