jqwidgets-ng 17.1.1 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,506 +1,506 @@
1
- /* tslint:disable */
2
- /* eslint-disable */
3
- /*!
4
- * Globalize
5
- *
6
- * http://github.com/jquery/globalize
7
- *
8
- * Copyright Software Freedom Conservancy, Inc.
9
- * Dual licensed under the MIT or GPL Version 2 licenses.
10
- * http://jquery.org/license
11
- */
12
-
13
- (function( window, undefined ) {
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /*!
4
+ * Globalize
5
+ *
6
+ * http://github.com/jquery/globalize
7
+ *
8
+ * Copyright Software Freedom Conservancy, Inc.
9
+ * Dual licensed under the MIT or GPL Version 2 licenses.
10
+ * http://jquery.org/license
11
+ */
12
+
13
+ (function( window, undefined ) {
14
14
  if (document.Globalize) {
15
15
  return;
16
- }
17
-
18
- var Globalize,
19
- // private variables
20
- regexHex,
21
- regexInfinity,
22
- regexParseFloat,
23
- regexTrim,
24
- // private JavaScript utility functions
25
- arrayIndexOf,
26
- endsWith,
27
- extend,
28
- isArray,
29
- isFunction,
30
- isObject,
31
- startsWith,
32
- trim,
33
- truncate,
34
- zeroPad,
35
- // private Globalization utility functions
36
- appendPreOrPostMatch,
37
- expandFormat,
38
- formatDate,
39
- formatNumber,
40
- getTokenRegExp,
41
- getEra,
42
- getEraYear,
43
- parseExact,
44
- parseNegativePattern;
45
-
46
- // Global variable (Globalize) or CommonJS module (globalize)
47
- Globalize = function( cultureSelector ) {
48
- return new Globalize.prototype.init( cultureSelector );
49
- };
50
-
51
- if ( typeof require !== "undefined" &&
52
- typeof exports !== "undefined" &&
53
- typeof module !== "undefined" ) {
54
- // Assume CommonJS
55
- module.exports = Globalize;
56
- } else {
57
- // Export as global variable
58
- window.Globalize = Globalize;
59
- }
60
-
61
- Globalize.cultures = {};
62
-
63
- Globalize.prototype = {
64
- constructor: Globalize,
65
- init: function( cultureSelector ) {
66
- this.cultures = Globalize.cultures;
67
- this.cultureSelector = cultureSelector;
68
-
69
- return this;
70
- }
71
- };
72
- Globalize.prototype.init.prototype = Globalize.prototype;
73
-
74
- // 1. When defining a culture, all fields are required except the ones stated as optional.
75
- // 2. Each culture should have a ".calendars" object with at least one calendar named "standard"
76
- // which serves as the default calendar in use by that culture.
77
- // 3. Each culture should have a ".calendar" object which is the current calendar being used,
78
- // it may be dynamically changed at any time to one of the calendars in ".calendars".
79
- Globalize.cultures[ "default" ] = {
80
- // A unique name for the culture in the form <language code>-<country/region code>
81
- name: "en",
82
- // the name of the culture in the english language
83
- englishName: "English",
84
- // the name of the culture in its own language
85
- nativeName: "English",
86
- // whether the culture uses right-to-left text
87
- isRTL: false,
88
- // "language" is used for so-called "specific" cultures.
89
- // For example, the culture "es-CL" means "Spanish, in Chili".
90
- // It represents the Spanish-speaking culture as it is in Chili,
91
- // which might have different formatting rules or even translations
92
- // than Spanish in Spain. A "neutral" culture is one that is not
93
- // specific to a region. For example, the culture "es" is the generic
94
- // Spanish culture, which may be a more generalized version of the language
95
- // that may or may not be what a specific culture expects.
96
- // For a specific culture like "es-CL", the "language" field refers to the
97
- // neutral, generic culture information for the language it is using.
98
- // This is not always a simple matter of the string before the dash.
99
- // For example, the "zh-Hans" culture is netural (Simplified Chinese).
100
- // And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage
101
- // field is "zh-CHS", not "zh".
102
- // This field should be used to navigate from a specific culture to it's
103
- // more general, neutral culture. If a culture is already as general as it
104
- // can get, the language may refer to itself.
105
- language: "en",
106
- // numberFormat defines general number formatting rules, like the digits in
107
- // each grouping, the group separator, and how negative numbers are displayed.
108
- numberFormat: {
109
- // [negativePattern]
110
- // Note, numberFormat.pattern has no "positivePattern" unlike percent and currency,
111
- // but is still defined as an array for consistency with them.
112
- // negativePattern: one of "(n)|-n|- n|n-|n -"
113
- pattern: [ "-n" ],
114
- // number of decimal places normally shown
115
- decimals: 2,
116
- // string that separates number groups, as in 1,000,000
117
- ",": ",",
118
- // string that separates a number from the fractional portion, as in 1.99
119
- ".": ".",
120
- // array of numbers indicating the size of each number group.
121
- // TODO: more detailed description and example
122
- groupSizes: [ 3 ],
123
- // symbol used for positive numbers
124
- "+": "+",
125
- // symbol used for negative numbers
126
- "-": "-",
127
- // symbol used for NaN (Not-A-Number)
128
- "NaN": "NaN",
129
- // symbol used for Negative Infinity
130
- negativeInfinity: "-Infinity",
131
- // symbol used for Positive Infinity
132
- positiveInfinity: "Infinity",
133
- percent: {
134
- // [negativePattern, positivePattern]
135
- // negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %"
136
- // positivePattern: one of "n %|n%|%n|% n"
137
- pattern: [ "-n %", "n %" ],
138
- // number of decimal places normally shown
139
- decimals: 2,
140
- // array of numbers indicating the size of each number group.
141
- // TODO: more detailed description and example
142
- groupSizes: [ 3 ],
143
- // string that separates number groups, as in 1,000,000
144
- ",": ",",
145
- // string that separates a number from the fractional portion, as in 1.99
146
- ".": ".",
147
- // symbol used to represent a percentage
148
- symbol: "%"
149
- },
150
- currency: {
151
- // [negativePattern, positivePattern]
152
- // negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)"
153
- // positivePattern: one of "$n|n$|$ n|n $"
154
- pattern: [ "($n)", "$n" ],
155
- // number of decimal places normally shown
156
- decimals: 2,
157
- // array of numbers indicating the size of each number group.
158
- // TODO: more detailed description and example
159
- groupSizes: [ 3 ],
160
- // string that separates number groups, as in 1,000,000
161
- ",": ",",
162
- // string that separates a number from the fractional portion, as in 1.99
163
- ".": ".",
164
- // symbol used to represent currency
165
- symbol: "$"
166
- }
167
- },
168
- // calendars defines all the possible calendars used by this culture.
169
- // There should be at least one defined with name "standard", and is the default
170
- // calendar used by the culture.
171
- // A calendar contains information about how dates are formatted, information about
172
- // the calendar's eras, a standard set of the date formats,
173
- // translations for day and month names, and if the calendar is not based on the Gregorian
174
- // calendar, conversion functions to and from the Gregorian calendar.
175
- calendars: {
176
- standard: {
177
- // name that identifies the type of calendar this is
178
- name: "Gregorian_USEnglish",
179
- // separator of parts of a date (e.g. "/" in 11/05/1955)
180
- "/": "/",
181
- // separator of parts of a time (e.g. ":" in 05:44 PM)
182
- ":": ":",
183
- // the first day of the week (0 = Sunday, 1 = Monday, etc)
184
- firstDay: 0,
185
- days: {
186
- // full day names
187
- names: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
188
- // abbreviated day names
189
- namesAbbr: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
190
- // shortest day names
191
- namesShort: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ]
192
- },
193
- months: {
194
- // full month names (13 months for lunar calendards -- 13th month should be "" if not lunar)
195
- names: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "" ],
196
- // abbreviated month names
197
- namesAbbr: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" ]
198
- },
199
- // AM and PM designators in one of these forms:
200
- // The usual view, and the upper and lower case versions
201
- // [ standard, lowercase, uppercase ]
202
- // The culture does not use AM or PM (likely all standard date formats use 24 hour time)
203
- // null
204
- AM: [ "AM", "am", "AM" ],
205
- PM: [ "PM", "pm", "PM" ],
206
- eras: [
207
- // eras in reverse chronological order.
208
- // name: the name of the era in this culture (e.g. A.D., C.E.)
209
- // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era.
210
- // offset: offset in years from gregorian calendar
211
- {
212
- "name": "A.D.",
213
- "start": null,
214
- "offset": 0
215
- }
216
- ],
217
- // when a two digit year is given, it will never be parsed as a four digit
218
- // year greater than this year (in the appropriate era for the culture)
219
- // Set it as a full year (e.g. 2029) or use an offset format starting from
220
- // the current year: "+19" would correspond to 2029 if the current year 2010.
221
- twoDigitYearMax: 2029,
222
- // set of predefined date and time patterns used by the culture
223
- // these represent the format someone in this culture would expect
224
- // to see given the portions of the date that are shown.
225
- patterns: {
226
- // short date pattern
227
- d: "M/d/yyyy",
228
- // long date pattern
229
- D: "dddd, MMMM dd, yyyy",
230
- // short time pattern
231
- t: "h:mm tt",
232
- // long time pattern
233
- T: "h:mm:ss tt",
234
- // long date, short time pattern
235
- f: "dddd, MMMM dd, yyyy h:mm tt",
236
- // long date, long time pattern
237
- F: "dddd, MMMM dd, yyyy h:mm:ss tt",
238
- // month/day pattern
239
- M: "MMMM dd",
240
- // month/year pattern
241
- Y: "yyyy MMMM",
242
- // S is a sortable format that does not vary by culture
243
- S: "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss"
244
- }
245
- // optional fields for each calendar:
246
- /*
247
- monthsGenitive:
248
- Same as months but used when the day preceeds the month.
249
- Omit if the culture has no genitive distinction in month names.
250
- For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx
251
- convert:
252
- Allows for the support of non-gregorian based calendars. This convert object is used to
253
- to convert a date to and from a gregorian calendar date to handle parsing and formatting.
254
- The two functions:
255
- fromGregorian( date )
256
- Given the date as a parameter, return an array with parts [ year, month, day ]
257
- corresponding to the non-gregorian based year, month, and day for the calendar.
258
- toGregorian( year, month, day )
259
- Given the non-gregorian year, month, and day, return a new Date() object
260
- set to the corresponding date in the gregorian calendar.
261
- */
262
- }
263
- },
264
- // For localized strings
265
- messages: {}
266
- };
267
-
268
- Globalize.cultures[ "default" ].calendar = Globalize.cultures[ "default" ].calendars.standard;
269
-
270
- Globalize.cultures.en = Globalize.cultures[ "default" ];
271
-
272
- Globalize.cultureSelector = "en";
273
-
274
- //
275
- // private variables
276
- //
277
-
278
- regexHex = /^0x[a-f0-9]+$/i;
279
- regexInfinity = /^[+\-]?infinity$/i;
280
- regexParseFloat = /^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/;
281
- regexTrim = /^\s+|\s+$/g;
282
-
283
- //
284
- // private JavaScript utility functions
285
- //
286
-
287
- arrayIndexOf = function( array, item ) {
288
- if ( array.indexOf ) {
289
- return array.indexOf( item );
290
- }
291
- for ( var i = 0, length = array.length; i < length; i++ ) {
292
- if ( array[i] === item ) {
293
- return i;
294
- }
295
- }
296
- return -1;
297
- };
298
-
299
- endsWith = function( value, pattern ) {
300
- return value.substr( value.length - pattern.length ) === pattern;
301
- };
302
-
303
- extend = function() {
304
- var options, name, src, copy, copyIsArray, clone,
305
- target = arguments[0] || {},
306
- i = 1,
307
- length = arguments.length,
308
- deep = false;
309
-
310
- // Handle a deep copy situation
311
- if ( typeof target === "boolean" ) {
312
- deep = target;
313
- target = arguments[1] || {};
314
- // skip the boolean and the target
315
- i = 2;
316
- }
317
-
318
- // Handle case when target is a string or something (possible in deep copy)
319
- if ( typeof target !== "object" && !isFunction(target) ) {
320
- target = {};
321
- }
322
-
323
- for ( ; i < length; i++ ) {
324
- // Only deal with non-null/undefined values
325
- if ( (options = arguments[ i ]) != null ) {
326
- // Extend the base object
327
- for ( name in options ) {
328
- src = target[ name ];
329
- copy = options[ name ];
330
-
331
- // Prevent never-ending loop
332
- if ( target === copy ) {
333
- continue;
334
- }
335
-
336
- // Recurse if we're merging plain objects or arrays
337
- if ( deep && copy && ( isObject(copy) || (copyIsArray = isArray(copy)) ) ) {
338
- if ( copyIsArray ) {
339
- copyIsArray = false;
340
- clone = src && isArray(src) ? src : [];
341
-
342
- } else {
343
- clone = src && isObject(src) ? src : {};
344
- }
345
-
346
- // Never move original objects, clone them
347
- target[ name ] = extend( deep, clone, copy );
348
-
349
- // Don't bring in undefined values
350
- } else if ( copy !== undefined ) {
351
- target[ name ] = copy;
352
- }
353
- }
354
- }
355
- }
356
-
357
- // Return the modified object
358
- return target;
359
- };
360
-
361
- isArray = Array.isArray || function( obj ) {
362
- return Object.prototype.toString.call( obj ) === "[object Array]";
363
- };
364
-
365
- isFunction = function( obj ) {
366
- return Object.prototype.toString.call( obj ) === "[object Function]";
367
- };
368
-
369
- isObject = function( obj ) {
370
- return Object.prototype.toString.call( obj ) === "[object Object]";
371
- };
372
-
373
- startsWith = function( value, pattern ) {
374
- return value.indexOf( pattern ) === 0;
375
- };
376
-
377
- trim = function( value ) {
378
- return ( value + "" ).replace( regexTrim, "" );
379
- };
380
-
381
- truncate = function( value ) {
382
- if ( isNaN( value ) ) {
383
- return NaN;
384
- }
385
- return Math[ value < 0 ? "ceil" : "floor" ]( value );
386
- };
387
-
388
- zeroPad = function( str, count, left ) {
389
- var l;
390
- for ( l = str.length; l < count; l += 1 ) {
391
- str = ( left ? ("0" + str) : (str + "0") );
392
- }
393
- return str;
394
- };
395
-
396
- //
397
- // private Globalization utility functions
398
- //
399
-
400
- appendPreOrPostMatch = function( preMatch, strings ) {
401
- // appends pre- and post- token match strings while removing escaped characters.
402
- // Returns a single quote count which is used to determine if the token occurs
403
- // in a string literal.
404
- var quoteCount = 0,
405
- escaped = false;
406
- for ( var i = 0, il = preMatch.length; i < il; i++ ) {
407
- var c = preMatch.charAt( i );
408
- switch ( c ) {
409
- case "\'":
410
- if ( escaped ) {
411
- strings.push( "\'" );
412
- }
413
- else {
414
- quoteCount++;
415
- }
416
- escaped = false;
417
- break;
418
- case "\\":
419
- if ( escaped ) {
420
- strings.push( "\\" );
421
- }
422
- escaped = !escaped;
423
- break;
424
- default:
425
- strings.push( c );
426
- escaped = false;
427
- break;
428
- }
429
- }
430
- return quoteCount;
431
- };
432
-
433
- expandFormat = function( cal, format ) {
434
- // expands unspecified or single character date formats into the full pattern.
435
- format = format || "F";
436
- var pattern,
437
- patterns = cal.patterns,
438
- len = format.length;
439
- if ( len === 1 ) {
440
- pattern = patterns[ format ];
441
- if ( !pattern ) {
442
- throw "Invalid date format string \'" + format + "\'.";
443
- }
444
- format = pattern;
445
- }
446
- else if ( len === 2 && format.charAt(0) === "%" ) {
447
- // %X escape format -- intended as a custom format string that is only one character, not a built-in format.
448
- format = format.charAt( 1 );
449
- }
450
- return format;
451
- };
452
-
453
- formatDate = function( value, format, culture ) {
454
- var cal = culture.calendar,
455
- convert = cal.convert,
456
- ret;
457
-
458
- if ( !format || !format.length || format === "i" ) {
459
- if ( culture && culture.name.length ) {
460
- if ( convert ) {
461
- // non-gregorian calendar, so we cannot use built-in toLocaleString()
462
- ret = formatDate( value, cal.patterns.F, culture );
463
- }
464
- else {
465
- var eraDate = new Date( value.getTime() ),
466
- era = getEra( value, cal.eras );
467
- eraDate.setFullYear( getEraYear(value, cal, era) );
468
- ret = eraDate.toLocaleString();
469
- }
470
- }
471
- else {
472
- ret = value.toString();
473
- }
474
- return ret;
475
- }
476
-
477
- var eras = cal.eras,
478
- sortable = format === "s";
479
- format = expandFormat( cal, format );
480
-
481
- // Start with an empty string
482
- ret = [];
483
- var hour,
484
- zeros = [ "0", "00", "000" ],
485
- foundDay,
486
- checkedDay,
487
- dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g,
488
- quoteCount = 0,
489
- tokenRegExp = getTokenRegExp(),
490
- converted;
491
-
492
- //function padZeros( num, c ) {
493
- // var r, s = num + "";
494
- // if ( c > 1 && s.length < c ) {
495
- // r = ( zeros[c - 2] + s);
496
- // return r.substr( r.length - c, c );
497
- // }
498
- // else {
499
- // r = s;
500
- // }
501
- // return r;
502
- //}
503
-
16
+ }
17
+
18
+ var Globalize,
19
+ // private variables
20
+ regexHex,
21
+ regexInfinity,
22
+ regexParseFloat,
23
+ regexTrim,
24
+ // private JavaScript utility functions
25
+ arrayIndexOf,
26
+ endsWith,
27
+ extend,
28
+ isArray,
29
+ isFunction,
30
+ isObject,
31
+ startsWith,
32
+ trim,
33
+ truncate,
34
+ zeroPad,
35
+ // private Globalization utility functions
36
+ appendPreOrPostMatch,
37
+ expandFormat,
38
+ formatDate,
39
+ formatNumber,
40
+ getTokenRegExp,
41
+ getEra,
42
+ getEraYear,
43
+ parseExact,
44
+ parseNegativePattern;
45
+
46
+ // Global variable (Globalize) or CommonJS module (globalize)
47
+ Globalize = function( cultureSelector ) {
48
+ return new Globalize.prototype.init( cultureSelector );
49
+ };
50
+
51
+ if ( typeof require !== "undefined" &&
52
+ typeof exports !== "undefined" &&
53
+ typeof module !== "undefined" ) {
54
+ // Assume CommonJS
55
+ module.exports = Globalize;
56
+ } else {
57
+ // Export as global variable
58
+ window.Globalize = Globalize;
59
+ }
60
+
61
+ Globalize.cultures = {};
62
+
63
+ Globalize.prototype = {
64
+ constructor: Globalize,
65
+ init: function( cultureSelector ) {
66
+ this.cultures = Globalize.cultures;
67
+ this.cultureSelector = cultureSelector;
68
+
69
+ return this;
70
+ }
71
+ };
72
+ Globalize.prototype.init.prototype = Globalize.prototype;
73
+
74
+ // 1. When defining a culture, all fields are required except the ones stated as optional.
75
+ // 2. Each culture should have a ".calendars" object with at least one calendar named "standard"
76
+ // which serves as the default calendar in use by that culture.
77
+ // 3. Each culture should have a ".calendar" object which is the current calendar being used,
78
+ // it may be dynamically changed at any time to one of the calendars in ".calendars".
79
+ Globalize.cultures[ "default" ] = {
80
+ // A unique name for the culture in the form <language code>-<country/region code>
81
+ name: "en",
82
+ // the name of the culture in the english language
83
+ englishName: "English",
84
+ // the name of the culture in its own language
85
+ nativeName: "English",
86
+ // whether the culture uses right-to-left text
87
+ isRTL: false,
88
+ // "language" is used for so-called "specific" cultures.
89
+ // For example, the culture "es-CL" means "Spanish, in Chili".
90
+ // It represents the Spanish-speaking culture as it is in Chili,
91
+ // which might have different formatting rules or even translations
92
+ // than Spanish in Spain. A "neutral" culture is one that is not
93
+ // specific to a region. For example, the culture "es" is the generic
94
+ // Spanish culture, which may be a more generalized version of the language
95
+ // that may or may not be what a specific culture expects.
96
+ // For a specific culture like "es-CL", the "language" field refers to the
97
+ // neutral, generic culture information for the language it is using.
98
+ // This is not always a simple matter of the string before the dash.
99
+ // For example, the "zh-Hans" culture is netural (Simplified Chinese).
100
+ // And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage
101
+ // field is "zh-CHS", not "zh".
102
+ // This field should be used to navigate from a specific culture to it's
103
+ // more general, neutral culture. If a culture is already as general as it
104
+ // can get, the language may refer to itself.
105
+ language: "en",
106
+ // numberFormat defines general number formatting rules, like the digits in
107
+ // each grouping, the group separator, and how negative numbers are displayed.
108
+ numberFormat: {
109
+ // [negativePattern]
110
+ // Note, numberFormat.pattern has no "positivePattern" unlike percent and currency,
111
+ // but is still defined as an array for consistency with them.
112
+ // negativePattern: one of "(n)|-n|- n|n-|n -"
113
+ pattern: [ "-n" ],
114
+ // number of decimal places normally shown
115
+ decimals: 2,
116
+ // string that separates number groups, as in 1,000,000
117
+ ",": ",",
118
+ // string that separates a number from the fractional portion, as in 1.99
119
+ ".": ".",
120
+ // array of numbers indicating the size of each number group.
121
+ // TODO: more detailed description and example
122
+ groupSizes: [ 3 ],
123
+ // symbol used for positive numbers
124
+ "+": "+",
125
+ // symbol used for negative numbers
126
+ "-": "-",
127
+ // symbol used for NaN (Not-A-Number)
128
+ "NaN": "NaN",
129
+ // symbol used for Negative Infinity
130
+ negativeInfinity: "-Infinity",
131
+ // symbol used for Positive Infinity
132
+ positiveInfinity: "Infinity",
133
+ percent: {
134
+ // [negativePattern, positivePattern]
135
+ // negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %"
136
+ // positivePattern: one of "n %|n%|%n|% n"
137
+ pattern: [ "-n %", "n %" ],
138
+ // number of decimal places normally shown
139
+ decimals: 2,
140
+ // array of numbers indicating the size of each number group.
141
+ // TODO: more detailed description and example
142
+ groupSizes: [ 3 ],
143
+ // string that separates number groups, as in 1,000,000
144
+ ",": ",",
145
+ // string that separates a number from the fractional portion, as in 1.99
146
+ ".": ".",
147
+ // symbol used to represent a percentage
148
+ symbol: "%"
149
+ },
150
+ currency: {
151
+ // [negativePattern, positivePattern]
152
+ // negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)"
153
+ // positivePattern: one of "$n|n$|$ n|n $"
154
+ pattern: [ "($n)", "$n" ],
155
+ // number of decimal places normally shown
156
+ decimals: 2,
157
+ // array of numbers indicating the size of each number group.
158
+ // TODO: more detailed description and example
159
+ groupSizes: [ 3 ],
160
+ // string that separates number groups, as in 1,000,000
161
+ ",": ",",
162
+ // string that separates a number from the fractional portion, as in 1.99
163
+ ".": ".",
164
+ // symbol used to represent currency
165
+ symbol: "$"
166
+ }
167
+ },
168
+ // calendars defines all the possible calendars used by this culture.
169
+ // There should be at least one defined with name "standard", and is the default
170
+ // calendar used by the culture.
171
+ // A calendar contains information about how dates are formatted, information about
172
+ // the calendar's eras, a standard set of the date formats,
173
+ // translations for day and month names, and if the calendar is not based on the Gregorian
174
+ // calendar, conversion functions to and from the Gregorian calendar.
175
+ calendars: {
176
+ standard: {
177
+ // name that identifies the type of calendar this is
178
+ name: "Gregorian_USEnglish",
179
+ // separator of parts of a date (e.g. "/" in 11/05/1955)
180
+ "/": "/",
181
+ // separator of parts of a time (e.g. ":" in 05:44 PM)
182
+ ":": ":",
183
+ // the first day of the week (0 = Sunday, 1 = Monday, etc)
184
+ firstDay: 0,
185
+ days: {
186
+ // full day names
187
+ names: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
188
+ // abbreviated day names
189
+ namesAbbr: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
190
+ // shortest day names
191
+ namesShort: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ]
192
+ },
193
+ months: {
194
+ // full month names (13 months for lunar calendards -- 13th month should be "" if not lunar)
195
+ names: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "" ],
196
+ // abbreviated month names
197
+ namesAbbr: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" ]
198
+ },
199
+ // AM and PM designators in one of these forms:
200
+ // The usual view, and the upper and lower case versions
201
+ // [ standard, lowercase, uppercase ]
202
+ // The culture does not use AM or PM (likely all standard date formats use 24 hour time)
203
+ // null
204
+ AM: [ "AM", "am", "AM" ],
205
+ PM: [ "PM", "pm", "PM" ],
206
+ eras: [
207
+ // eras in reverse chronological order.
208
+ // name: the name of the era in this culture (e.g. A.D., C.E.)
209
+ // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era.
210
+ // offset: offset in years from gregorian calendar
211
+ {
212
+ "name": "A.D.",
213
+ "start": null,
214
+ "offset": 0
215
+ }
216
+ ],
217
+ // when a two digit year is given, it will never be parsed as a four digit
218
+ // year greater than this year (in the appropriate era for the culture)
219
+ // Set it as a full year (e.g. 2029) or use an offset format starting from
220
+ // the current year: "+19" would correspond to 2029 if the current year 2010.
221
+ twoDigitYearMax: 2029,
222
+ // set of predefined date and time patterns used by the culture
223
+ // these represent the format someone in this culture would expect
224
+ // to see given the portions of the date that are shown.
225
+ patterns: {
226
+ // short date pattern
227
+ d: "M/d/yyyy",
228
+ // long date pattern
229
+ D: "dddd, MMMM dd, yyyy",
230
+ // short time pattern
231
+ t: "h:mm tt",
232
+ // long time pattern
233
+ T: "h:mm:ss tt",
234
+ // long date, short time pattern
235
+ f: "dddd, MMMM dd, yyyy h:mm tt",
236
+ // long date, long time pattern
237
+ F: "dddd, MMMM dd, yyyy h:mm:ss tt",
238
+ // month/day pattern
239
+ M: "MMMM dd",
240
+ // month/year pattern
241
+ Y: "yyyy MMMM",
242
+ // S is a sortable format that does not vary by culture
243
+ S: "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss"
244
+ }
245
+ // optional fields for each calendar:
246
+ /*
247
+ monthsGenitive:
248
+ Same as months but used when the day preceeds the month.
249
+ Omit if the culture has no genitive distinction in month names.
250
+ For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx
251
+ convert:
252
+ Allows for the support of non-gregorian based calendars. This convert object is used to
253
+ to convert a date to and from a gregorian calendar date to handle parsing and formatting.
254
+ The two functions:
255
+ fromGregorian( date )
256
+ Given the date as a parameter, return an array with parts [ year, month, day ]
257
+ corresponding to the non-gregorian based year, month, and day for the calendar.
258
+ toGregorian( year, month, day )
259
+ Given the non-gregorian year, month, and day, return a new Date() object
260
+ set to the corresponding date in the gregorian calendar.
261
+ */
262
+ }
263
+ },
264
+ // For localized strings
265
+ messages: {}
266
+ };
267
+
268
+ Globalize.cultures[ "default" ].calendar = Globalize.cultures[ "default" ].calendars.standard;
269
+
270
+ Globalize.cultures.en = Globalize.cultures[ "default" ];
271
+
272
+ Globalize.cultureSelector = "en";
273
+
274
+ //
275
+ // private variables
276
+ //
277
+
278
+ regexHex = /^0x[a-f0-9]+$/i;
279
+ regexInfinity = /^[+\-]?infinity$/i;
280
+ regexParseFloat = /^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/;
281
+ regexTrim = /^\s+|\s+$/g;
282
+
283
+ //
284
+ // private JavaScript utility functions
285
+ //
286
+
287
+ arrayIndexOf = function( array, item ) {
288
+ if ( array.indexOf ) {
289
+ return array.indexOf( item );
290
+ }
291
+ for ( var i = 0, length = array.length; i < length; i++ ) {
292
+ if ( array[i] === item ) {
293
+ return i;
294
+ }
295
+ }
296
+ return -1;
297
+ };
298
+
299
+ endsWith = function( value, pattern ) {
300
+ return value.substr( value.length - pattern.length ) === pattern;
301
+ };
302
+
303
+ extend = function() {
304
+ var options, name, src, copy, copyIsArray, clone,
305
+ target = arguments[0] || {},
306
+ i = 1,
307
+ length = arguments.length,
308
+ deep = false;
309
+
310
+ // Handle a deep copy situation
311
+ if ( typeof target === "boolean" ) {
312
+ deep = target;
313
+ target = arguments[1] || {};
314
+ // skip the boolean and the target
315
+ i = 2;
316
+ }
317
+
318
+ // Handle case when target is a string or something (possible in deep copy)
319
+ if ( typeof target !== "object" && !isFunction(target) ) {
320
+ target = {};
321
+ }
322
+
323
+ for ( ; i < length; i++ ) {
324
+ // Only deal with non-null/undefined values
325
+ if ( (options = arguments[ i ]) != null ) {
326
+ // Extend the base object
327
+ for ( name in options ) {
328
+ src = target[ name ];
329
+ copy = options[ name ];
330
+
331
+ // Prevent never-ending loop
332
+ if ( target === copy ) {
333
+ continue;
334
+ }
335
+
336
+ // Recurse if we're merging plain objects or arrays
337
+ if ( deep && copy && ( isObject(copy) || (copyIsArray = isArray(copy)) ) ) {
338
+ if ( copyIsArray ) {
339
+ copyIsArray = false;
340
+ clone = src && isArray(src) ? src : [];
341
+
342
+ } else {
343
+ clone = src && isObject(src) ? src : {};
344
+ }
345
+
346
+ // Never move original objects, clone them
347
+ target[ name ] = extend( deep, clone, copy );
348
+
349
+ // Don't bring in undefined values
350
+ } else if ( copy !== undefined ) {
351
+ target[ name ] = copy;
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ // Return the modified object
358
+ return target;
359
+ };
360
+
361
+ isArray = Array.isArray || function( obj ) {
362
+ return Object.prototype.toString.call( obj ) === "[object Array]";
363
+ };
364
+
365
+ isFunction = function( obj ) {
366
+ return Object.prototype.toString.call( obj ) === "[object Function]";
367
+ };
368
+
369
+ isObject = function( obj ) {
370
+ return Object.prototype.toString.call( obj ) === "[object Object]";
371
+ };
372
+
373
+ startsWith = function( value, pattern ) {
374
+ return value.indexOf( pattern ) === 0;
375
+ };
376
+
377
+ trim = function( value ) {
378
+ return ( value + "" ).replace( regexTrim, "" );
379
+ };
380
+
381
+ truncate = function( value ) {
382
+ if ( isNaN( value ) ) {
383
+ return NaN;
384
+ }
385
+ return Math[ value < 0 ? "ceil" : "floor" ]( value );
386
+ };
387
+
388
+ zeroPad = function( str, count, left ) {
389
+ var l;
390
+ for ( l = str.length; l < count; l += 1 ) {
391
+ str = ( left ? ("0" + str) : (str + "0") );
392
+ }
393
+ return str;
394
+ };
395
+
396
+ //
397
+ // private Globalization utility functions
398
+ //
399
+
400
+ appendPreOrPostMatch = function( preMatch, strings ) {
401
+ // appends pre- and post- token match strings while removing escaped characters.
402
+ // Returns a single quote count which is used to determine if the token occurs
403
+ // in a string literal.
404
+ var quoteCount = 0,
405
+ escaped = false;
406
+ for ( var i = 0, il = preMatch.length; i < il; i++ ) {
407
+ var c = preMatch.charAt( i );
408
+ switch ( c ) {
409
+ case "\'":
410
+ if ( escaped ) {
411
+ strings.push( "\'" );
412
+ }
413
+ else {
414
+ quoteCount++;
415
+ }
416
+ escaped = false;
417
+ break;
418
+ case "\\":
419
+ if ( escaped ) {
420
+ strings.push( "\\" );
421
+ }
422
+ escaped = !escaped;
423
+ break;
424
+ default:
425
+ strings.push( c );
426
+ escaped = false;
427
+ break;
428
+ }
429
+ }
430
+ return quoteCount;
431
+ };
432
+
433
+ expandFormat = function( cal, format ) {
434
+ // expands unspecified or single character date formats into the full pattern.
435
+ format = format || "F";
436
+ var pattern,
437
+ patterns = cal.patterns,
438
+ len = format.length;
439
+ if ( len === 1 ) {
440
+ pattern = patterns[ format ];
441
+ if ( !pattern ) {
442
+ throw "Invalid date format string \'" + format + "\'.";
443
+ }
444
+ format = pattern;
445
+ }
446
+ else if ( len === 2 && format.charAt(0) === "%" ) {
447
+ // %X escape format -- intended as a custom format string that is only one character, not a built-in format.
448
+ format = format.charAt( 1 );
449
+ }
450
+ return format;
451
+ };
452
+
453
+ formatDate = function( value, format, culture ) {
454
+ var cal = culture.calendar,
455
+ convert = cal.convert,
456
+ ret;
457
+
458
+ if ( !format || !format.length || format === "i" ) {
459
+ if ( culture && culture.name.length ) {
460
+ if ( convert ) {
461
+ // non-gregorian calendar, so we cannot use built-in toLocaleString()
462
+ ret = formatDate( value, cal.patterns.F, culture );
463
+ }
464
+ else {
465
+ var eraDate = new Date( value.getTime() ),
466
+ era = getEra( value, cal.eras );
467
+ eraDate.setFullYear( getEraYear(value, cal, era) );
468
+ ret = eraDate.toLocaleString();
469
+ }
470
+ }
471
+ else {
472
+ ret = value.toString();
473
+ }
474
+ return ret;
475
+ }
476
+
477
+ var eras = cal.eras,
478
+ sortable = format === "s";
479
+ format = expandFormat( cal, format );
480
+
481
+ // Start with an empty string
482
+ ret = [];
483
+ var hour,
484
+ zeros = [ "0", "00", "000" ],
485
+ foundDay,
486
+ checkedDay,
487
+ dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g,
488
+ quoteCount = 0,
489
+ tokenRegExp = getTokenRegExp(),
490
+ converted;
491
+
492
+ //function padZeros( num, c ) {
493
+ // var r, s = num + "";
494
+ // if ( c > 1 && s.length < c ) {
495
+ // r = ( zeros[c - 2] + s);
496
+ // return r.substr( r.length - c, c );
497
+ // }
498
+ // else {
499
+ // r = s;
500
+ // }
501
+ // return r;
502
+ //}
503
+
504
504
  function padZeros(num, c) {
505
505
  if (num < 0) {
506
506
  return "-" + padZeros(-num, c);
@@ -514,1094 +514,1094 @@ formatDate = function( value, format, culture ) {
514
514
  r = s;
515
515
  }
516
516
  return r;
517
- }
518
-
519
- function hasDay() {
520
- if ( foundDay || checkedDay ) {
521
- return foundDay;
522
- }
523
- foundDay = dayPartRegExp.test( format );
524
- checkedDay = true;
525
- return foundDay;
526
- }
527
-
528
- function getPart( date, part ) {
529
- if ( converted ) {
530
- return converted[ part ];
531
- }
532
- switch ( part ) {
533
- case 0:
534
- return date.getFullYear();
535
- case 1:
536
- return date.getMonth();
537
- case 2:
538
- return date.getDate();
539
- default:
540
- throw "Invalid part value " + part;
541
- }
542
- }
543
-
544
- if ( !sortable && convert ) {
545
- converted = convert.fromGregorian( value );
546
- }
547
-
548
- for ( ; ; ) {
549
- // Save the current index
550
- var index = tokenRegExp.lastIndex,
551
- // Look for the next pattern
552
- ar = tokenRegExp.exec( format );
553
-
554
- // Append the text before the pattern (or the end of the string if not found)
555
- var preMatch = format.slice( index, ar ? ar.index : format.length );
556
- quoteCount += appendPreOrPostMatch( preMatch, ret );
557
-
558
- if ( !ar ) {
559
- break;
560
- }
561
-
562
- // do not replace any matches that occur inside a string literal.
563
- if ( quoteCount % 2 ) {
564
- ret.push( ar[0] );
565
- continue;
566
- }
567
-
568
- var current = ar[ 0 ],
569
- clength = current.length;
570
-
571
- switch ( current ) {
572
- case "ddd":
573
- //Day of the week, as a three-letter abbreviation
574
- case "dddd":
575
- // Day of the week, using the full name
576
- var names = ( clength === 3 ) ? cal.days.namesAbbr : cal.days.names;
577
- ret.push( names[value.getDay()] );
578
- break;
579
- case "d":
580
- // Day of month, without leading zero for single-digit days
581
- case "dd":
582
- // Day of month, with leading zero for single-digit days
583
- foundDay = true;
584
- ret.push(
585
- padZeros( getPart(value, 2), clength )
586
- );
587
- break;
588
- case "MMM":
589
- // Month, as a three-letter abbreviation
590
- case "MMMM":
591
- // Month, using the full name
592
- var part = getPart( value, 1 );
593
- ret.push(
594
- ( cal.monthsGenitive && hasDay() ) ?
595
- ( cal.monthsGenitive[ clength === 3 ? "namesAbbr" : "names" ][ part ] ) :
596
- ( cal.months[ clength === 3 ? "namesAbbr" : "names" ][ part ] )
597
- );
598
- break;
599
- case "M":
600
- // Month, as digits, with no leading zero for single-digit months
601
- case "MM":
602
- // Month, as digits, with leading zero for single-digit months
603
- ret.push(
604
- padZeros( getPart(value, 1) + 1, clength )
605
- );
606
- break;
607
- case "y":
608
- // Year, as two digits, but with no leading zero for years less than 10
609
- case "yy":
610
- // Year, as two digits, with leading zero for years less than 10
611
- case "yyyy":
612
- // Year represented by four full digits
613
- part = converted ? converted[ 0 ] : getEraYear( value, cal, getEra(value, eras), sortable );
614
- if ( clength < 4 ) {
615
- part = part % 100;
616
- }
617
- ret.push(
618
- padZeros( part, clength )
619
- );
620
- break;
621
- case "h":
622
- // Hours with no leading zero for single-digit hours, using 12-hour clock
623
- case "hh":
624
- // Hours with leading zero for single-digit hours, using 12-hour clock
625
- hour = value.getHours() % 12;
626
- if ( hour === 0 ) hour = 12;
627
- ret.push(
628
- padZeros( hour, clength )
629
- );
630
- break;
631
- case "H":
632
- // Hours with no leading zero for single-digit hours, using 24-hour clock
633
- case "HH":
634
- // Hours with leading zero for single-digit hours, using 24-hour clock
635
- ret.push(
636
- padZeros( value.getHours(), clength )
637
- );
638
- break;
639
- case "m":
640
- // Minutes with no leading zero for single-digit minutes
641
- case "mm":
642
- // Minutes with leading zero for single-digit minutes
643
- ret.push(
644
- padZeros( value.getMinutes(), clength )
645
- );
646
- break;
647
- case "s":
648
- // Seconds with no leading zero for single-digit seconds
649
- case "ss":
650
- // Seconds with leading zero for single-digit seconds
651
- ret.push(
652
- padZeros( value.getSeconds(), clength )
653
- );
654
- break;
655
- case "t":
656
- // One character am/pm indicator ("a" or "p")
657
- case "tt":
658
- // Multicharacter am/pm indicator
659
- part = value.getHours() < 12 ? ( cal.AM ? cal.AM[0] : " " ) : ( cal.PM ? cal.PM[0] : " " );
660
- ret.push( clength === 1 ? part.charAt(0) : part );
661
- break;
662
- case "f":
663
- // Deciseconds
664
- case "ff":
665
- // Centiseconds
666
- case "fff":
667
- // Milliseconds
668
- ret.push(
669
- padZeros( value.getMilliseconds(), 3 ).substr( 0, clength )
670
- );
671
- break;
672
- case "z":
673
- // Time zone offset, no leading zero
674
- case "zz":
675
- // Time zone offset with leading zero
676
- hour = value.getTimezoneOffset() / 60;
677
- ret.push(
678
- ( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), clength )
679
- );
680
- break;
681
- case "zzz":
682
- // Time zone offset with leading zero
683
- hour = value.getTimezoneOffset() / 60;
684
- ret.push(
685
- ( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), 2 ) +
686
- // Hard coded ":" separator, rather than using cal.TimeSeparator
687
- // Repeated here for consistency, plus ":" was already assumed in date parsing.
688
- ":" + padZeros( Math.abs(value.getTimezoneOffset() % 60), 2 )
689
- );
690
- break;
691
- case "g":
692
- case "gg":
693
- if ( cal.eras ) {
694
- ret.push(
695
- cal.eras[ getEra(value, eras) ].name
696
- );
697
- }
698
- break;
699
- case "/":
700
- ret.push( cal["/"] );
701
- break;
702
- default:
703
- throw "Invalid date format pattern \'" + current + "\'.";
704
- }
705
- }
706
- return ret.join( "" );
707
- };
708
-
709
- // formatNumber
710
- (function() {
711
- var expandNumber;
712
-
713
- expandNumber = function( number, precision, formatInfo ) {
714
- var groupSizes = formatInfo.groupSizes,
715
- curSize = groupSizes[ 0 ],
716
- curGroupIndex = 1,
717
- factor = Math.pow( 10, precision ),
718
- rounded = Math.round( number * factor ) / factor;
719
-
720
- if ( !isFinite(rounded) ) {
721
- rounded = number;
722
- }
723
- number = rounded;
724
-
725
- var numberString = number+"",
726
- right = "",
727
- split = numberString.split( /e/i ),
728
- exponent = split.length > 1 ? parseInt( split[1], 10 ) : 0;
729
- numberString = split[ 0 ];
730
- split = numberString.split( "." );
731
- numberString = split[ 0 ];
732
- right = split.length > 1 ? split[ 1 ] : "";
733
-
734
- var l;
735
- if ( exponent > 0 ) {
736
- right = zeroPad( right, exponent, false );
737
- numberString += right.slice( 0, exponent );
738
- right = right.substr( exponent );
739
- }
740
- else if ( exponent < 0 ) {
741
- exponent = -exponent;
742
- numberString = zeroPad( numberString, exponent + 1, true );
743
- right = numberString.slice( -exponent, numberString.length ) + right;
744
- numberString = numberString.slice( 0, -exponent );
745
- }
746
-
747
- if ( precision > 0 ) {
748
- right = formatInfo[ "." ] +
749
- ( (right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision) );
750
- }
751
- else {
752
- right = "";
753
- }
754
-
755
- var stringIndex = numberString.length - 1,
756
- sep = formatInfo[ "," ],
757
- ret = "";
758
-
759
- while ( stringIndex >= 0 ) {
760
- if ( curSize === 0 || curSize > stringIndex ) {
761
- return numberString.slice( 0, stringIndex + 1 ) + ( ret.length ? (sep + ret + right) : right );
762
- }
763
- ret = numberString.slice( stringIndex - curSize + 1, stringIndex + 1 ) + ( ret.length ? (sep + ret) : "" );
764
-
765
- stringIndex -= curSize;
766
-
767
- if ( curGroupIndex < groupSizes.length ) {
768
- curSize = groupSizes[ curGroupIndex ];
769
- curGroupIndex++;
770
- }
771
- }
772
-
773
- return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right;
774
- };
775
-
776
- formatNumber = function( value, format, culture ) {
777
- if ( !isFinite(value) ) {
778
- if ( value === Infinity ) {
779
- return culture.numberFormat.positiveInfinity;
780
- }
781
- if ( value === -Infinity ) {
782
- return culture.numberFormat.negativeInfinity;
783
- }
784
- return culture.numberFormat.NaN;
785
- }
786
- if ( !format || format === "i" ) {
787
- return culture.name.length ? value.toLocaleString() : value.toString();
788
- }
789
- format = format || "D";
790
-
791
- var nf = culture.numberFormat,
792
- number = Math.abs( value ),
793
- precision = -1,
794
- pattern;
795
- if ( format.length > 1 ) precision = parseInt( format.slice(1), 10 );
796
-
797
- var current = format.charAt( 0 ).toUpperCase(),
798
- formatInfo;
799
-
800
- switch ( current ) {
801
- case "D":
802
- pattern = "n";
803
- number = truncate( number );
804
- if ( precision !== -1 ) {
805
- number = zeroPad( "" + number, precision, true );
806
- }
807
- if ( value < 0 ) number = "-" + number;
808
- break;
809
- case "N":
810
- formatInfo = nf;
811
- /* falls through */
812
- case "C":
813
- formatInfo = formatInfo || nf.currency;
814
- /* falls through */
815
- case "P":
816
- formatInfo = formatInfo || nf.percent;
817
- pattern = value < 0 ? formatInfo.pattern[ 0 ] : ( formatInfo.pattern[1] || "n" );
818
- if ( precision === -1 ) precision = formatInfo.decimals;
819
- number = expandNumber( number * (current === "P" ? 100 : 1), precision, formatInfo );
820
- break;
821
- default:
822
- throw "Bad number format specifier: " + current;
823
- }
824
-
825
- var patternParts = /n|\$|-|%/g,
826
- ret = "";
827
- for ( ; ; ) {
828
- var index = patternParts.lastIndex,
829
- ar = patternParts.exec( pattern );
830
-
831
- ret += pattern.slice( index, ar ? ar.index : pattern.length );
832
-
833
- if ( !ar ) {
834
- break;
835
- }
836
-
837
- switch ( ar[0] ) {
838
- case "n":
839
- ret += number;
840
- break;
841
- case "$":
842
- ret += nf.currency.symbol;
843
- break;
844
- case "-":
845
- // don't make 0 negative
846
- if ( /[1-9]/.test(number) ) {
847
- ret += nf[ "-" ];
848
- }
849
- break;
850
- case "%":
851
- ret += nf.percent.symbol;
852
- break;
853
- }
854
- }
855
-
856
- return ret;
857
- };
858
-
859
- }());
860
-
861
- getTokenRegExp = function() {
862
- // regular expression for matching date and time tokens in format strings.
863
- return (/\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g);
864
- };
865
-
866
- getEra = function( date, eras ) {
867
- if ( !eras ) return 0;
868
- var start, ticks = date.getTime();
869
- for ( var i = 0, l = eras.length; i < l; i++ ) {
870
- start = eras[ i ].start;
871
- if ( start === null || ticks >= start ) {
872
- return i;
873
- }
874
- }
875
- return 0;
876
- };
877
-
878
- getEraYear = function( date, cal, era, sortable ) {
879
- var year = date.getFullYear();
880
- if ( !sortable && cal.eras ) {
881
- // convert normal gregorian year to era-shifted gregorian
882
- // year by subtracting the era offset
883
- year -= cal.eras[ era ].offset;
884
- }
885
- return year;
886
- };
887
-
888
- // parseExact
889
- (function() {
890
- var expandYear,
891
- getDayIndex,
892
- getMonthIndex,
893
- getParseRegExp,
894
- outOfRange,
895
- toUpper,
896
- toUpperArray;
897
-
898
- expandYear = function( cal, year ) {
899
- // expands 2-digit year into 4 digits.
900
- if ( year < 100 ) {
901
- var now = new Date(),
902
- era = getEra( now ),
903
- curr = getEraYear( now, cal, era ),
904
- twoDigitYearMax = cal.twoDigitYearMax;
905
- twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
906
- year += curr - ( curr % 100 );
907
- if ( year > twoDigitYearMax ) {
908
- year -= 100;
909
- }
910
- }
911
- return year;
912
- };
913
-
914
- getDayIndex = function ( cal, value, abbr ) {
915
- var ret,
916
- days = cal.days,
917
- upperDays = cal._upperDays;
918
- if ( !upperDays ) {
919
- cal._upperDays = upperDays = [
920
- toUpperArray( days.names ),
921
- toUpperArray( days.namesAbbr ),
922
- toUpperArray( days.namesShort )
923
- ];
924
- }
925
- value = toUpper( value );
926
- if ( abbr ) {
927
- ret = arrayIndexOf( upperDays[1], value );
928
- if ( ret === -1 ) {
929
- ret = arrayIndexOf( upperDays[2], value );
930
- }
931
- }
932
- else {
933
- ret = arrayIndexOf( upperDays[0], value );
934
- }
935
- return ret;
936
- };
937
-
938
- getMonthIndex = function( cal, value, abbr ) {
939
- var months = cal.months,
940
- monthsGen = cal.monthsGenitive || cal.months,
941
- upperMonths = cal._upperMonths,
942
- upperMonthsGen = cal._upperMonthsGen;
943
- if ( !upperMonths ) {
944
- cal._upperMonths = upperMonths = [
945
- toUpperArray( months.names ),
946
- toUpperArray( months.namesAbbr )
947
- ];
948
- cal._upperMonthsGen = upperMonthsGen = [
949
- toUpperArray( monthsGen.names ),
950
- toUpperArray( monthsGen.namesAbbr )
951
- ];
952
- }
953
- value = toUpper( value );
954
- var i = arrayIndexOf( abbr ? upperMonths[1] : upperMonths[0], value );
955
- if ( i < 0 ) {
956
- i = arrayIndexOf( abbr ? upperMonthsGen[1] : upperMonthsGen[0], value );
957
- }
958
- return i;
959
- };
960
-
961
- getParseRegExp = function( cal, format ) {
962
- // converts a format string into a regular expression with groups that
963
- // can be used to extract date fields from a date string.
964
- // check for a cached parse regex.
965
- var re = cal._parseRegExp;
966
- if ( !re ) {
967
- cal._parseRegExp = re = {};
968
- }
969
- else {
970
- var reFormat = re[ format ];
971
- if ( reFormat ) {
972
- return reFormat;
973
- }
974
- }
975
-
976
- // expand single digit formats, then escape regular expression characters.
977
- var expFormat = expandFormat( cal, format ).replace( /([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g, "\\\\$1" ),
978
- regexp = [ "^" ],
979
- groups = [],
980
- index = 0,
981
- quoteCount = 0,
982
- tokenRegExp = getTokenRegExp(),
983
- match;
984
-
985
- // iterate through each date token found.
986
- while ( (match = tokenRegExp.exec(expFormat)) !== null ) {
987
- var preMatch = expFormat.slice( index, match.index );
988
- index = tokenRegExp.lastIndex;
989
-
990
- // don't replace any matches that occur inside a string literal.
991
- quoteCount += appendPreOrPostMatch( preMatch, regexp );
992
- if ( quoteCount % 2 ) {
993
- regexp.push( match[0] );
994
- continue;
995
- }
996
-
997
- // add a regex group for the token.
998
- var m = match[ 0 ],
999
- len = m.length,
1000
- add;
1001
- switch ( m ) {
1002
- case "dddd": case "ddd":
1003
- case "MMMM": case "MMM":
1004
- case "gg": case "g":
1005
- add = "(\\D+)";
1006
- break;
1007
- case "tt": case "t":
1008
- add = "(\\D*)";
1009
- break;
1010
- case "yyyy":
1011
- case "fff":
1012
- case "ff":
1013
- case "f":
1014
- add = "(\\d{" + len + "})";
1015
- break;
1016
- case "dd": case "d":
1017
- case "MM": case "M":
1018
- case "yy": case "y":
1019
- case "HH": case "H":
1020
- case "hh": case "h":
1021
- case "mm": case "m":
1022
- case "ss": case "s":
1023
- add = "(\\d\\d?)";
1024
- break;
1025
- case "zzz":
1026
- add = "([+-]?\\d\\d?:\\d{2})";
1027
- break;
1028
- case "zz": case "z":
1029
- add = "([+-]?\\d\\d?)";
1030
- break;
1031
- case "/":
1032
- add = "(\\/)";
1033
- break;
1034
- default:
1035
- throw "Invalid date format pattern \'" + m + "\'.";
1036
- }
1037
- if ( add ) {
1038
- regexp.push( add );
1039
- }
1040
- groups.push( match[0] );
1041
- }
1042
- appendPreOrPostMatch( expFormat.slice(index), regexp );
1043
- regexp.push( "$" );
1044
-
1045
- // allow whitespace to differ when matching formats.
1046
- var regexpStr = regexp.join( "" ).replace( /\s+/g, "\\s+" ),
1047
- parseRegExp = { "regExp": regexpStr, "groups": groups };
1048
-
1049
- // cache the regex for this format.
1050
- return re[ format ] = parseRegExp;
1051
- };
1052
-
1053
- outOfRange = function( value, low, high ) {
1054
- return value < low || value > high;
1055
- };
1056
-
1057
- toUpper = function( value ) {
1058
- // "he-IL" has non-breaking space in weekday names.
1059
- return value.split( "\u00A0" ).join( " " ).toUpperCase();
1060
- };
1061
-
1062
- toUpperArray = function( arr ) {
1063
- var results = [];
1064
- for ( var i = 0, l = arr.length; i < l; i++ ) {
1065
- results[ i ] = toUpper( arr[i] );
1066
- }
1067
- return results;
1068
- };
1069
-
1070
- parseExact = function( value, format, culture ) {
1071
- // try to parse the date string by matching against the format string
1072
- // while using the specified culture for date field names.
1073
- value = trim( value );
1074
- var cal = culture.calendar,
1075
- // convert date formats into regular expressions with groupings.
1076
- // use the regexp to determine the input format and extract the date fields.
1077
- parseInfo = getParseRegExp( cal, format ),
1078
- match = new RegExp( parseInfo.regExp ).exec( value );
1079
- if ( match === null ) {
1080
- return null;
1081
- }
1082
- // found a date format that matches the input.
1083
- var groups = parseInfo.groups,
1084
- era = null, year = null, month = null, date = null, weekDay = null,
1085
- hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null,
1086
- pmHour = false;
1087
- // iterate the format groups to extract and set the date fields.
1088
- for ( var j = 0, jl = groups.length; j < jl; j++ ) {
1089
- var matchGroup = match[ j + 1 ];
1090
- if ( matchGroup ) {
1091
- var current = groups[ j ],
1092
- clength = current.length,
1093
- matchInt = parseInt( matchGroup, 10 );
1094
- switch ( current ) {
1095
- case "dd": case "d":
1096
- // Day of month.
1097
- date = matchInt;
1098
- // check that date is generally in valid range, also checking overflow below.
1099
- if ( outOfRange(date, 1, 31) ) return null;
1100
- break;
1101
- case "MMM": case "MMMM":
1102
- month = getMonthIndex( cal, matchGroup, clength === 3 );
1103
- if ( outOfRange(month, 0, 11) ) return null;
1104
- break;
1105
- case "M": case "MM":
1106
- // Month.
1107
- month = matchInt - 1;
1108
- if ( outOfRange(month, 0, 11) ) return null;
1109
- break;
1110
- case "y": case "yy":
1111
- case "yyyy":
1112
- year = clength < 4 ? expandYear( cal, matchInt ) : matchInt;
1113
- if ( outOfRange(year, 0, 9999) ) return null;
1114
- break;
1115
- case "h": case "hh":
1116
- // Hours (12-hour clock).
1117
- hour = matchInt;
1118
- if ( hour === 12 ) hour = 0;
1119
- if ( outOfRange(hour, 0, 11) ) return null;
1120
- break;
1121
- case "H": case "HH":
1122
- // Hours (24-hour clock).
1123
- hour = matchInt;
1124
- if ( outOfRange(hour, 0, 23) ) return null;
1125
- break;
1126
- case "m": case "mm":
1127
- // Minutes.
1128
- min = matchInt;
1129
- if ( outOfRange(min, 0, 59) ) return null;
1130
- break;
1131
- case "s": case "ss":
1132
- // Seconds.
1133
- sec = matchInt;
1134
- if ( outOfRange(sec, 0, 59) ) return null;
1135
- break;
1136
- case "tt": case "t":
1137
- // AM/PM designator.
1138
- // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of
1139
- // the AM tokens. If not, fail the parse for this format.
1140
- pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] );
1141
- if (
1142
- !pmHour && (
1143
- !cal.AM || ( matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2] )
1144
- )
1145
- ) return null;
1146
- break;
1147
- case "f":
1148
- // Deciseconds.
1149
- case "ff":
1150
- // Centiseconds.
1151
- case "fff":
1152
- // Milliseconds.
1153
- msec = matchInt * Math.pow( 10, 3 - clength );
1154
- if ( outOfRange(msec, 0, 999) ) return null;
1155
- break;
1156
- case "ddd":
1157
- // Day of week.
1158
- case "dddd":
1159
- // Day of week.
1160
- weekDay = getDayIndex( cal, matchGroup, clength === 3 );
1161
- if ( outOfRange(weekDay, 0, 6) ) return null;
1162
- break;
1163
- case "zzz":
1164
- // Time zone offset in +/- hours:min.
1165
- var offsets = matchGroup.split( /:/ );
1166
- if ( offsets.length !== 2 ) return null;
1167
- hourOffset = parseInt( offsets[0], 10 );
1168
- if ( outOfRange(hourOffset, -12, 13) ) return null;
1169
- var minOffset = parseInt( offsets[1], 10 );
1170
- if ( outOfRange(minOffset, 0, 59) ) return null;
1171
- tzMinOffset = ( hourOffset * 60 ) + ( startsWith(matchGroup, "-") ? -minOffset : minOffset );
1172
- break;
1173
- case "z": case "zz":
1174
- // Time zone offset in +/- hours.
1175
- hourOffset = matchInt;
1176
- if ( outOfRange(hourOffset, -12, 13) ) return null;
1177
- tzMinOffset = hourOffset * 60;
1178
- break;
1179
- case "g": case "gg":
1180
- var eraName = matchGroup;
1181
- if ( !eraName || !cal.eras ) return null;
1182
- eraName = trim( eraName.toLowerCase() );
1183
- for ( var i = 0, l = cal.eras.length; i < l; i++ ) {
1184
- if ( eraName === cal.eras[i].name.toLowerCase() ) {
1185
- era = i;
1186
- break;
1187
- }
1188
- }
1189
- // could not find an era with that name
1190
- if ( era === null ) return null;
1191
- break;
1192
- }
1193
- }
1194
- }
1195
- var result = new Date(), defaultYear, convert = cal.convert;
1196
- defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear();
1197
- if ( year === null ) {
1198
- year = defaultYear;
1199
- }
1200
- else if ( cal.eras ) {
1201
- // year must be shifted to normal gregorian year
1202
- // but not if year was not specified, its already normal gregorian
1203
- // per the main if clause above.
1204
- year += cal.eras[( era || 0 )].offset;
1205
- }
1206
- // set default day and month to 1 and January, so if unspecified, these are the defaults
1207
- // instead of the current day/month.
1208
- if ( month === null ) {
1209
- month = 0;
1210
- }
1211
- if ( date === null ) {
1212
- date = 1;
1213
- }
1214
- // now have year, month, and date, but in the culture's calendar.
1215
- // convert to gregorian if necessary
1216
- if ( convert ) {
1217
- result = convert.toGregorian( year, month, date );
1218
- // conversion failed, must be an invalid match
1219
- if ( result === null ) return null;
1220
- }
1221
- else {
1222
- // have to set year, month and date together to avoid overflow based on current date.
1223
- result.setFullYear( year, month, date );
1224
- // check to see if date overflowed for specified month (only checked 1-31 above).
1225
- if ( result.getDate() !== date ) return null;
1226
- // invalid day of week.
1227
- if ( weekDay !== null && result.getDay() !== weekDay ) {
1228
- return null;
1229
- }
1230
- }
1231
- // if pm designator token was found make sure the hours fit the 24-hour clock.
1232
- if ( pmHour && hour < 12 ) {
1233
- hour += 12;
1234
- }
1235
- result.setHours( hour, min, sec, msec );
1236
- if ( tzMinOffset !== null ) {
1237
- // adjust timezone to utc before applying local offset.
1238
- var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() );
1239
- // Safari limits hours and minutes to the range of -127 to 127. We need to use setHours
1240
- // to ensure both these fields will not exceed this range. adjustedMin will range
1241
- // somewhere between -1440 and 1500, so we only need to split this into hours.
1242
- result.setHours( result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60 );
1243
- }
1244
- return result;
1245
- };
1246
- }());
1247
-
1248
- parseNegativePattern = function( value, nf, negativePattern ) {
1249
- var neg = nf[ "-" ],
1250
- pos = nf[ "+" ],
1251
- ret;
1252
- switch ( negativePattern ) {
1253
- case "n -":
1254
- neg = " " + neg;
1255
- pos = " " + pos;
1256
- /* falls through */
1257
- case "n-":
1258
- if ( endsWith(value, neg) ) {
1259
- ret = [ "-", value.substr(0, value.length - neg.length) ];
1260
- }
1261
- else if ( endsWith(value, pos) ) {
1262
- ret = [ "+", value.substr(0, value.length - pos.length) ];
1263
- }
1264
- break;
1265
- case "- n":
1266
- neg += " ";
1267
- pos += " ";
1268
- /* falls through */
1269
- case "-n":
1270
- if ( startsWith(value, neg) ) {
1271
- ret = [ "-", value.substr(neg.length) ];
1272
- }
1273
- else if ( startsWith(value, pos) ) {
1274
- ret = [ "+", value.substr(pos.length) ];
1275
- }
1276
- break;
1277
- case "(n)":
1278
- if ( startsWith(value, "(") && endsWith(value, ")") ) {
1279
- ret = [ "-", value.substr(1, value.length - 2) ];
1280
- }
1281
- break;
1282
- }
1283
- return ret || [ "", value ];
1284
- };
1285
-
1286
- //
1287
- // public instance functions
1288
- //
1289
-
1290
- Globalize.prototype.findClosestCulture = function( cultureSelector ) {
1291
- return Globalize.findClosestCulture.call( this, cultureSelector );
1292
- };
1293
-
1294
- Globalize.prototype.format = function( value, format, cultureSelector ) {
1295
- return Globalize.format.call( this, value, format, cultureSelector );
1296
- };
1297
-
1298
- Globalize.prototype.localize = function( key, cultureSelector ) {
1299
- return Globalize.localize.call( this, key, cultureSelector );
1300
- };
1301
-
1302
- Globalize.prototype.parseInt = function( value, radix, cultureSelector ) {
1303
- return Globalize.parseInt.call( this, value, radix, cultureSelector );
1304
- };
1305
-
1306
- Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) {
1307
- return Globalize.parseFloat.call( this, value, radix, cultureSelector );
1308
- };
1309
-
1310
- Globalize.prototype.culture = function( cultureSelector ) {
1311
- return Globalize.culture.call( this, cultureSelector );
1312
- };
1313
-
1314
- //
1315
- // public singleton functions
1316
- //
1317
-
1318
- Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) {
1319
-
1320
- var base = {},
1321
- isNew = false;
1322
-
1323
- if ( typeof cultureName !== "string" ) {
1324
- // cultureName argument is optional string. If not specified, assume info is first
1325
- // and only argument. Specified info deep-extends current culture.
1326
- info = cultureName;
1327
- cultureName = this.culture().name;
1328
- base = this.cultures[ cultureName ];
1329
- } else if ( typeof baseCultureName !== "string" ) {
1330
- // baseCultureName argument is optional string. If not specified, assume info is second
1331
- // argument. Specified info deep-extends specified culture.
1332
- // If specified culture does not exist, create by deep-extending default
1333
- info = baseCultureName;
1334
- isNew = ( this.cultures[ cultureName ] == null );
1335
- base = this.cultures[ cultureName ] || this.cultures[ "default" ];
1336
- } else {
1337
- // cultureName and baseCultureName specified. Assume a new culture is being created
1338
- // by deep-extending an specified base culture
1339
- isNew = true;
1340
- base = this.cultures[ baseCultureName ];
1341
- }
1342
-
1343
- this.cultures[ cultureName ] = extend(true, {},
1344
- base,
1345
- info
1346
- );
1347
- // Make the standard calendar the current culture if it's a new culture
1348
- if ( isNew ) {
1349
- this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard;
1350
- }
1351
- };
1352
-
1353
- Globalize.findClosestCulture = function( name ) {
1354
- var match;
1355
- if ( !name ) {
1356
- return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ];
1357
- }
1358
- if ( typeof name === "string" ) {
1359
- name = name.split( "," );
1360
- }
1361
- if ( isArray(name) ) {
1362
- var lang,
1363
- cultures = this.cultures,
1364
- list = name,
1365
- i, l = list.length,
1366
- prioritized = [];
1367
- for ( i = 0; i < l; i++ ) {
1368
- name = trim( list[i] );
1369
- var pri, parts = name.split( ";" );
1370
- lang = trim( parts[0] );
1371
- if ( parts.length === 1 ) {
1372
- pri = 1;
1373
- }
1374
- else {
1375
- name = trim( parts[1] );
1376
- if ( name.indexOf("q=") === 0 ) {
1377
- name = name.substr( 2 );
1378
- pri = parseFloat( name );
1379
- pri = isNaN( pri ) ? 0 : pri;
1380
- }
1381
- else {
1382
- pri = 1;
1383
- }
1384
- }
1385
- prioritized.push({ lang: lang, pri: pri });
1386
- }
1387
- prioritized.sort(function( a, b ) {
1388
- if ( a.pri < b.pri ) {
1389
- return 1;
1390
- } else if ( a.pri > b.pri ) {
1391
- return -1;
1392
- }
1393
- return 0;
1394
- });
1395
- // exact match
1396
- for ( i = 0; i < l; i++ ) {
1397
- lang = prioritized[ i ].lang;
1398
- match = cultures[ lang ];
1399
- if ( match ) {
1400
- return match;
1401
- }
1402
- }
1403
-
1404
- // neutral language match
1405
- for ( i = 0; i < l; i++ ) {
1406
- lang = prioritized[ i ].lang;
1407
- do {
1408
- var index = lang.lastIndexOf( "-" );
1409
- if ( index === -1 ) {
1410
- break;
1411
- }
1412
- // strip off the last part. e.g. en-US => en
1413
- lang = lang.substr( 0, index );
1414
- match = cultures[ lang ];
1415
- if ( match ) {
1416
- return match;
1417
- }
1418
- }
1419
- while ( 1 );
1420
- }
1421
-
1422
- // last resort: match first culture using that language
1423
- for ( i = 0; i < l; i++ ) {
1424
- lang = prioritized[ i ].lang;
1425
- for ( var cultureKey in cultures ) {
1426
- var culture = cultures[ cultureKey ];
1427
- if ( culture.language == lang ) {
1428
- return culture;
1429
- }
1430
- }
1431
- }
1432
- }
1433
- else if ( typeof name === "object" ) {
1434
- return name;
1435
- }
1436
- return match || null;
1437
- };
1438
-
1439
- Globalize.format = function( value, format, cultureSelector ) {
1440
- var culture = this.findClosestCulture( cultureSelector );
1441
- if ( value instanceof Date ) {
1442
- value = formatDate( value, format, culture );
1443
- }
1444
- else if ( typeof value === "number" ) {
1445
- value = formatNumber( value, format, culture );
1446
- }
1447
- return value;
1448
- };
1449
-
1450
- Globalize.localize = function( key, cultureSelector ) {
1451
- return this.findClosestCulture( cultureSelector ).messages[ key ] ||
1452
- this.cultures[ "default" ].messages[ key ];
1453
- };
1454
-
1455
- Globalize.parseDate = function( value, formats, culture ) {
1456
- culture = this.findClosestCulture( culture );
1457
-
1458
- var date, prop, patterns;
1459
- if ( formats ) {
1460
- if ( typeof formats === "string" ) {
1461
- formats = [ formats ];
1462
- }
1463
- if ( formats.length ) {
1464
- for ( var i = 0, l = formats.length; i < l; i++ ) {
1465
- var format = formats[ i ];
1466
- if ( format ) {
1467
- date = parseExact( value, format, culture );
1468
- if ( date ) {
1469
- break;
1470
- }
1471
- }
1472
- }
1473
- }
1474
- } else {
1475
- patterns = culture.calendar.patterns;
1476
- for ( prop in patterns ) {
1477
- date = parseExact( value, patterns[prop], culture );
1478
- if ( date ) {
1479
- break;
1480
- }
1481
- }
1482
- }
1483
-
1484
- return date || null;
1485
- };
1486
-
1487
- Globalize.parseInt = function( value, radix, cultureSelector ) {
1488
- return truncate( Globalize.parseFloat(value, radix, cultureSelector) );
1489
- };
1490
-
1491
- Globalize.parseFloat = function( value, radix, cultureSelector ) {
1492
- // radix argument is optional
1493
- if ( typeof radix !== "number" ) {
1494
- cultureSelector = radix;
1495
- radix = 10;
1496
- }
1497
-
1498
- var culture = this.findClosestCulture( cultureSelector );
1499
- var ret = NaN,
1500
- nf = culture.numberFormat;
1501
-
1502
- if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) {
1503
- // remove currency symbol
1504
- value = value.replace( culture.numberFormat.currency.symbol, "" );
1505
- // replace decimal seperator
1506
- value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] );
1507
- }
1508
-
1509
- //Remove percentage character from number string before parsing
1510
- if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){
1511
- value = value.replace( culture.numberFormat.percent.symbol, "" );
1512
- }
1513
-
1514
- // remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR
1515
- value = value.replace( / /g, "" );
1516
-
1517
- // allow infinity or hexidecimal
1518
- if ( regexInfinity.test(value) ) {
1519
- ret = parseFloat( value );
1520
- }
1521
- else if ( !radix && regexHex.test(value) ) {
1522
- ret = parseInt( value, 16 );
1523
- }
1524
- else {
1525
-
1526
- // determine sign and number
1527
- var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
1528
- sign = signInfo[ 0 ],
1529
- num = signInfo[ 1 ];
1530
-
1531
- // #44 - try parsing as "(n)"
1532
- if ( sign === "" && nf.pattern[0] !== "(n)" ) {
1533
- signInfo = parseNegativePattern( value, nf, "(n)" );
1534
- sign = signInfo[ 0 ];
1535
- num = signInfo[ 1 ];
1536
- }
1537
-
1538
- // try parsing as "-n"
1539
- if ( sign === "" && nf.pattern[0] !== "-n" ) {
1540
- signInfo = parseNegativePattern( value, nf, "-n" );
1541
- sign = signInfo[ 0 ];
1542
- num = signInfo[ 1 ];
1543
- }
1544
-
1545
- sign = sign || "+";
1546
-
1547
- // determine exponent and number
1548
- var exponent,
1549
- intAndFraction,
1550
- exponentPos = num.indexOf( "e" );
1551
- if ( exponentPos < 0 ) exponentPos = num.indexOf( "E" );
1552
- if ( exponentPos < 0 ) {
1553
- intAndFraction = num;
1554
- exponent = null;
1555
- }
1556
- else {
1557
- intAndFraction = num.substr( 0, exponentPos );
1558
- exponent = num.substr( exponentPos + 1 );
1559
- }
1560
- // determine decimal position
1561
- var integer,
1562
- fraction,
1563
- decSep = nf[ "." ],
1564
- decimalPos = intAndFraction.indexOf( decSep );
1565
- if ( decimalPos < 0 ) {
1566
- integer = intAndFraction;
1567
- fraction = null;
1568
- }
1569
- else {
1570
- integer = intAndFraction.substr( 0, decimalPos );
1571
- fraction = intAndFraction.substr( decimalPos + decSep.length );
1572
- }
1573
- // handle groups (e.g. 1,000,000)
1574
- var groupSep = nf[ "," ];
1575
- integer = integer.split( groupSep ).join( "" );
1576
- var altGroupSep = groupSep.replace( /\u00A0/g, " " );
1577
- if ( groupSep !== altGroupSep ) {
1578
- integer = integer.split( altGroupSep ).join( "" );
1579
- }
1580
- // build a natively parsable number string
1581
- var p = sign + integer;
1582
- if ( fraction !== null ) {
1583
- p += "." + fraction;
1584
- }
1585
- if ( exponent !== null ) {
1586
- // exponent itself may have a number patternd
1587
- var expSignInfo = parseNegativePattern( exponent, nf, "-n" );
1588
- p += "e" + ( expSignInfo[0] || "+" ) + expSignInfo[ 1 ];
1589
- }
1590
- if ( regexParseFloat.test(p) ) {
1591
- ret = parseFloat( p );
1592
- }
1593
- }
1594
- return ret;
1595
- };
1596
-
1597
- Globalize.culture = function( cultureSelector ) {
1598
- // setter
1599
- if ( typeof cultureSelector !== "undefined" ) {
1600
- this.cultureSelector = cultureSelector;
1601
- }
1602
- // getter
1603
- return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ];
1604
- };
1605
-
1606
- document.Globalize = Globalize;
517
+ }
518
+
519
+ function hasDay() {
520
+ if ( foundDay || checkedDay ) {
521
+ return foundDay;
522
+ }
523
+ foundDay = dayPartRegExp.test( format );
524
+ checkedDay = true;
525
+ return foundDay;
526
+ }
527
+
528
+ function getPart( date, part ) {
529
+ if ( converted ) {
530
+ return converted[ part ];
531
+ }
532
+ switch ( part ) {
533
+ case 0:
534
+ return date.getFullYear();
535
+ case 1:
536
+ return date.getMonth();
537
+ case 2:
538
+ return date.getDate();
539
+ default:
540
+ throw "Invalid part value " + part;
541
+ }
542
+ }
543
+
544
+ if ( !sortable && convert ) {
545
+ converted = convert.fromGregorian( value );
546
+ }
547
+
548
+ for ( ; ; ) {
549
+ // Save the current index
550
+ var index = tokenRegExp.lastIndex,
551
+ // Look for the next pattern
552
+ ar = tokenRegExp.exec( format );
553
+
554
+ // Append the text before the pattern (or the end of the string if not found)
555
+ var preMatch = format.slice( index, ar ? ar.index : format.length );
556
+ quoteCount += appendPreOrPostMatch( preMatch, ret );
557
+
558
+ if ( !ar ) {
559
+ break;
560
+ }
561
+
562
+ // do not replace any matches that occur inside a string literal.
563
+ if ( quoteCount % 2 ) {
564
+ ret.push( ar[0] );
565
+ continue;
566
+ }
567
+
568
+ var current = ar[ 0 ],
569
+ clength = current.length;
570
+
571
+ switch ( current ) {
572
+ case "ddd":
573
+ //Day of the week, as a three-letter abbreviation
574
+ case "dddd":
575
+ // Day of the week, using the full name
576
+ var names = ( clength === 3 ) ? cal.days.namesAbbr : cal.days.names;
577
+ ret.push( names[value.getDay()] );
578
+ break;
579
+ case "d":
580
+ // Day of month, without leading zero for single-digit days
581
+ case "dd":
582
+ // Day of month, with leading zero for single-digit days
583
+ foundDay = true;
584
+ ret.push(
585
+ padZeros( getPart(value, 2), clength )
586
+ );
587
+ break;
588
+ case "MMM":
589
+ // Month, as a three-letter abbreviation
590
+ case "MMMM":
591
+ // Month, using the full name
592
+ var part = getPart( value, 1 );
593
+ ret.push(
594
+ ( cal.monthsGenitive && hasDay() ) ?
595
+ ( cal.monthsGenitive[ clength === 3 ? "namesAbbr" : "names" ][ part ] ) :
596
+ ( cal.months[ clength === 3 ? "namesAbbr" : "names" ][ part ] )
597
+ );
598
+ break;
599
+ case "M":
600
+ // Month, as digits, with no leading zero for single-digit months
601
+ case "MM":
602
+ // Month, as digits, with leading zero for single-digit months
603
+ ret.push(
604
+ padZeros( getPart(value, 1) + 1, clength )
605
+ );
606
+ break;
607
+ case "y":
608
+ // Year, as two digits, but with no leading zero for years less than 10
609
+ case "yy":
610
+ // Year, as two digits, with leading zero for years less than 10
611
+ case "yyyy":
612
+ // Year represented by four full digits
613
+ part = converted ? converted[ 0 ] : getEraYear( value, cal, getEra(value, eras), sortable );
614
+ if ( clength < 4 ) {
615
+ part = part % 100;
616
+ }
617
+ ret.push(
618
+ padZeros( part, clength )
619
+ );
620
+ break;
621
+ case "h":
622
+ // Hours with no leading zero for single-digit hours, using 12-hour clock
623
+ case "hh":
624
+ // Hours with leading zero for single-digit hours, using 12-hour clock
625
+ hour = value.getHours() % 12;
626
+ if ( hour === 0 ) hour = 12;
627
+ ret.push(
628
+ padZeros( hour, clength )
629
+ );
630
+ break;
631
+ case "H":
632
+ // Hours with no leading zero for single-digit hours, using 24-hour clock
633
+ case "HH":
634
+ // Hours with leading zero for single-digit hours, using 24-hour clock
635
+ ret.push(
636
+ padZeros( value.getHours(), clength )
637
+ );
638
+ break;
639
+ case "m":
640
+ // Minutes with no leading zero for single-digit minutes
641
+ case "mm":
642
+ // Minutes with leading zero for single-digit minutes
643
+ ret.push(
644
+ padZeros( value.getMinutes(), clength )
645
+ );
646
+ break;
647
+ case "s":
648
+ // Seconds with no leading zero for single-digit seconds
649
+ case "ss":
650
+ // Seconds with leading zero for single-digit seconds
651
+ ret.push(
652
+ padZeros( value.getSeconds(), clength )
653
+ );
654
+ break;
655
+ case "t":
656
+ // One character am/pm indicator ("a" or "p")
657
+ case "tt":
658
+ // Multicharacter am/pm indicator
659
+ part = value.getHours() < 12 ? ( cal.AM ? cal.AM[0] : " " ) : ( cal.PM ? cal.PM[0] : " " );
660
+ ret.push( clength === 1 ? part.charAt(0) : part );
661
+ break;
662
+ case "f":
663
+ // Deciseconds
664
+ case "ff":
665
+ // Centiseconds
666
+ case "fff":
667
+ // Milliseconds
668
+ ret.push(
669
+ padZeros( value.getMilliseconds(), 3 ).substr( 0, clength )
670
+ );
671
+ break;
672
+ case "z":
673
+ // Time zone offset, no leading zero
674
+ case "zz":
675
+ // Time zone offset with leading zero
676
+ hour = value.getTimezoneOffset() / 60;
677
+ ret.push(
678
+ ( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), clength )
679
+ );
680
+ break;
681
+ case "zzz":
682
+ // Time zone offset with leading zero
683
+ hour = value.getTimezoneOffset() / 60;
684
+ ret.push(
685
+ ( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), 2 ) +
686
+ // Hard coded ":" separator, rather than using cal.TimeSeparator
687
+ // Repeated here for consistency, plus ":" was already assumed in date parsing.
688
+ ":" + padZeros( Math.abs(value.getTimezoneOffset() % 60), 2 )
689
+ );
690
+ break;
691
+ case "g":
692
+ case "gg":
693
+ if ( cal.eras ) {
694
+ ret.push(
695
+ cal.eras[ getEra(value, eras) ].name
696
+ );
697
+ }
698
+ break;
699
+ case "/":
700
+ ret.push( cal["/"] );
701
+ break;
702
+ default:
703
+ throw "Invalid date format pattern \'" + current + "\'.";
704
+ }
705
+ }
706
+ return ret.join( "" );
707
+ };
708
+
709
+ // formatNumber
710
+ (function() {
711
+ var expandNumber;
712
+
713
+ expandNumber = function( number, precision, formatInfo ) {
714
+ var groupSizes = formatInfo.groupSizes,
715
+ curSize = groupSizes[ 0 ],
716
+ curGroupIndex = 1,
717
+ factor = Math.pow( 10, precision ),
718
+ rounded = Math.round( number * factor ) / factor;
719
+
720
+ if ( !isFinite(rounded) ) {
721
+ rounded = number;
722
+ }
723
+ number = rounded;
724
+
725
+ var numberString = number+"",
726
+ right = "",
727
+ split = numberString.split( /e/i ),
728
+ exponent = split.length > 1 ? parseInt( split[1], 10 ) : 0;
729
+ numberString = split[ 0 ];
730
+ split = numberString.split( "." );
731
+ numberString = split[ 0 ];
732
+ right = split.length > 1 ? split[ 1 ] : "";
733
+
734
+ var l;
735
+ if ( exponent > 0 ) {
736
+ right = zeroPad( right, exponent, false );
737
+ numberString += right.slice( 0, exponent );
738
+ right = right.substr( exponent );
739
+ }
740
+ else if ( exponent < 0 ) {
741
+ exponent = -exponent;
742
+ numberString = zeroPad( numberString, exponent + 1, true );
743
+ right = numberString.slice( -exponent, numberString.length ) + right;
744
+ numberString = numberString.slice( 0, -exponent );
745
+ }
746
+
747
+ if ( precision > 0 ) {
748
+ right = formatInfo[ "." ] +
749
+ ( (right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision) );
750
+ }
751
+ else {
752
+ right = "";
753
+ }
754
+
755
+ var stringIndex = numberString.length - 1,
756
+ sep = formatInfo[ "," ],
757
+ ret = "";
758
+
759
+ while ( stringIndex >= 0 ) {
760
+ if ( curSize === 0 || curSize > stringIndex ) {
761
+ return numberString.slice( 0, stringIndex + 1 ) + ( ret.length ? (sep + ret + right) : right );
762
+ }
763
+ ret = numberString.slice( stringIndex - curSize + 1, stringIndex + 1 ) + ( ret.length ? (sep + ret) : "" );
764
+
765
+ stringIndex -= curSize;
766
+
767
+ if ( curGroupIndex < groupSizes.length ) {
768
+ curSize = groupSizes[ curGroupIndex ];
769
+ curGroupIndex++;
770
+ }
771
+ }
772
+
773
+ return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right;
774
+ };
775
+
776
+ formatNumber = function( value, format, culture ) {
777
+ if ( !isFinite(value) ) {
778
+ if ( value === Infinity ) {
779
+ return culture.numberFormat.positiveInfinity;
780
+ }
781
+ if ( value === -Infinity ) {
782
+ return culture.numberFormat.negativeInfinity;
783
+ }
784
+ return culture.numberFormat.NaN;
785
+ }
786
+ if ( !format || format === "i" ) {
787
+ return culture.name.length ? value.toLocaleString() : value.toString();
788
+ }
789
+ format = format || "D";
790
+
791
+ var nf = culture.numberFormat,
792
+ number = Math.abs( value ),
793
+ precision = -1,
794
+ pattern;
795
+ if ( format.length > 1 ) precision = parseInt( format.slice(1), 10 );
796
+
797
+ var current = format.charAt( 0 ).toUpperCase(),
798
+ formatInfo;
799
+
800
+ switch ( current ) {
801
+ case "D":
802
+ pattern = "n";
803
+ number = truncate( number );
804
+ if ( precision !== -1 ) {
805
+ number = zeroPad( "" + number, precision, true );
806
+ }
807
+ if ( value < 0 ) number = "-" + number;
808
+ break;
809
+ case "N":
810
+ formatInfo = nf;
811
+ /* falls through */
812
+ case "C":
813
+ formatInfo = formatInfo || nf.currency;
814
+ /* falls through */
815
+ case "P":
816
+ formatInfo = formatInfo || nf.percent;
817
+ pattern = value < 0 ? formatInfo.pattern[ 0 ] : ( formatInfo.pattern[1] || "n" );
818
+ if ( precision === -1 ) precision = formatInfo.decimals;
819
+ number = expandNumber( number * (current === "P" ? 100 : 1), precision, formatInfo );
820
+ break;
821
+ default:
822
+ throw "Bad number format specifier: " + current;
823
+ }
824
+
825
+ var patternParts = /n|\$|-|%/g,
826
+ ret = "";
827
+ for ( ; ; ) {
828
+ var index = patternParts.lastIndex,
829
+ ar = patternParts.exec( pattern );
830
+
831
+ ret += pattern.slice( index, ar ? ar.index : pattern.length );
832
+
833
+ if ( !ar ) {
834
+ break;
835
+ }
836
+
837
+ switch ( ar[0] ) {
838
+ case "n":
839
+ ret += number;
840
+ break;
841
+ case "$":
842
+ ret += nf.currency.symbol;
843
+ break;
844
+ case "-":
845
+ // don't make 0 negative
846
+ if ( /[1-9]/.test(number) ) {
847
+ ret += nf[ "-" ];
848
+ }
849
+ break;
850
+ case "%":
851
+ ret += nf.percent.symbol;
852
+ break;
853
+ }
854
+ }
855
+
856
+ return ret;
857
+ };
858
+
859
+ }());
860
+
861
+ getTokenRegExp = function() {
862
+ // regular expression for matching date and time tokens in format strings.
863
+ return (/\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g);
864
+ };
865
+
866
+ getEra = function( date, eras ) {
867
+ if ( !eras ) return 0;
868
+ var start, ticks = date.getTime();
869
+ for ( var i = 0, l = eras.length; i < l; i++ ) {
870
+ start = eras[ i ].start;
871
+ if ( start === null || ticks >= start ) {
872
+ return i;
873
+ }
874
+ }
875
+ return 0;
876
+ };
877
+
878
+ getEraYear = function( date, cal, era, sortable ) {
879
+ var year = date.getFullYear();
880
+ if ( !sortable && cal.eras ) {
881
+ // convert normal gregorian year to era-shifted gregorian
882
+ // year by subtracting the era offset
883
+ year -= cal.eras[ era ].offset;
884
+ }
885
+ return year;
886
+ };
887
+
888
+ // parseExact
889
+ (function() {
890
+ var expandYear,
891
+ getDayIndex,
892
+ getMonthIndex,
893
+ getParseRegExp,
894
+ outOfRange,
895
+ toUpper,
896
+ toUpperArray;
897
+
898
+ expandYear = function( cal, year ) {
899
+ // expands 2-digit year into 4 digits.
900
+ if ( year < 100 ) {
901
+ var now = new Date(),
902
+ era = getEra( now ),
903
+ curr = getEraYear( now, cal, era ),
904
+ twoDigitYearMax = cal.twoDigitYearMax;
905
+ twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
906
+ year += curr - ( curr % 100 );
907
+ if ( year > twoDigitYearMax ) {
908
+ year -= 100;
909
+ }
910
+ }
911
+ return year;
912
+ };
913
+
914
+ getDayIndex = function ( cal, value, abbr ) {
915
+ var ret,
916
+ days = cal.days,
917
+ upperDays = cal._upperDays;
918
+ if ( !upperDays ) {
919
+ cal._upperDays = upperDays = [
920
+ toUpperArray( days.names ),
921
+ toUpperArray( days.namesAbbr ),
922
+ toUpperArray( days.namesShort )
923
+ ];
924
+ }
925
+ value = toUpper( value );
926
+ if ( abbr ) {
927
+ ret = arrayIndexOf( upperDays[1], value );
928
+ if ( ret === -1 ) {
929
+ ret = arrayIndexOf( upperDays[2], value );
930
+ }
931
+ }
932
+ else {
933
+ ret = arrayIndexOf( upperDays[0], value );
934
+ }
935
+ return ret;
936
+ };
937
+
938
+ getMonthIndex = function( cal, value, abbr ) {
939
+ var months = cal.months,
940
+ monthsGen = cal.monthsGenitive || cal.months,
941
+ upperMonths = cal._upperMonths,
942
+ upperMonthsGen = cal._upperMonthsGen;
943
+ if ( !upperMonths ) {
944
+ cal._upperMonths = upperMonths = [
945
+ toUpperArray( months.names ),
946
+ toUpperArray( months.namesAbbr )
947
+ ];
948
+ cal._upperMonthsGen = upperMonthsGen = [
949
+ toUpperArray( monthsGen.names ),
950
+ toUpperArray( monthsGen.namesAbbr )
951
+ ];
952
+ }
953
+ value = toUpper( value );
954
+ var i = arrayIndexOf( abbr ? upperMonths[1] : upperMonths[0], value );
955
+ if ( i < 0 ) {
956
+ i = arrayIndexOf( abbr ? upperMonthsGen[1] : upperMonthsGen[0], value );
957
+ }
958
+ return i;
959
+ };
960
+
961
+ getParseRegExp = function( cal, format ) {
962
+ // converts a format string into a regular expression with groups that
963
+ // can be used to extract date fields from a date string.
964
+ // check for a cached parse regex.
965
+ var re = cal._parseRegExp;
966
+ if ( !re ) {
967
+ cal._parseRegExp = re = {};
968
+ }
969
+ else {
970
+ var reFormat = re[ format ];
971
+ if ( reFormat ) {
972
+ return reFormat;
973
+ }
974
+ }
975
+
976
+ // expand single digit formats, then escape regular expression characters.
977
+ var expFormat = expandFormat( cal, format ).replace( /([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g, "\\\\$1" ),
978
+ regexp = [ "^" ],
979
+ groups = [],
980
+ index = 0,
981
+ quoteCount = 0,
982
+ tokenRegExp = getTokenRegExp(),
983
+ match;
984
+
985
+ // iterate through each date token found.
986
+ while ( (match = tokenRegExp.exec(expFormat)) !== null ) {
987
+ var preMatch = expFormat.slice( index, match.index );
988
+ index = tokenRegExp.lastIndex;
989
+
990
+ // don't replace any matches that occur inside a string literal.
991
+ quoteCount += appendPreOrPostMatch( preMatch, regexp );
992
+ if ( quoteCount % 2 ) {
993
+ regexp.push( match[0] );
994
+ continue;
995
+ }
996
+
997
+ // add a regex group for the token.
998
+ var m = match[ 0 ],
999
+ len = m.length,
1000
+ add;
1001
+ switch ( m ) {
1002
+ case "dddd": case "ddd":
1003
+ case "MMMM": case "MMM":
1004
+ case "gg": case "g":
1005
+ add = "(\\D+)";
1006
+ break;
1007
+ case "tt": case "t":
1008
+ add = "(\\D*)";
1009
+ break;
1010
+ case "yyyy":
1011
+ case "fff":
1012
+ case "ff":
1013
+ case "f":
1014
+ add = "(\\d{" + len + "})";
1015
+ break;
1016
+ case "dd": case "d":
1017
+ case "MM": case "M":
1018
+ case "yy": case "y":
1019
+ case "HH": case "H":
1020
+ case "hh": case "h":
1021
+ case "mm": case "m":
1022
+ case "ss": case "s":
1023
+ add = "(\\d\\d?)";
1024
+ break;
1025
+ case "zzz":
1026
+ add = "([+-]?\\d\\d?:\\d{2})";
1027
+ break;
1028
+ case "zz": case "z":
1029
+ add = "([+-]?\\d\\d?)";
1030
+ break;
1031
+ case "/":
1032
+ add = "(\\/)";
1033
+ break;
1034
+ default:
1035
+ throw "Invalid date format pattern \'" + m + "\'.";
1036
+ }
1037
+ if ( add ) {
1038
+ regexp.push( add );
1039
+ }
1040
+ groups.push( match[0] );
1041
+ }
1042
+ appendPreOrPostMatch( expFormat.slice(index), regexp );
1043
+ regexp.push( "$" );
1044
+
1045
+ // allow whitespace to differ when matching formats.
1046
+ var regexpStr = regexp.join( "" ).replace( /\s+/g, "\\s+" ),
1047
+ parseRegExp = { "regExp": regexpStr, "groups": groups };
1048
+
1049
+ // cache the regex for this format.
1050
+ return re[ format ] = parseRegExp;
1051
+ };
1052
+
1053
+ outOfRange = function( value, low, high ) {
1054
+ return value < low || value > high;
1055
+ };
1056
+
1057
+ toUpper = function( value ) {
1058
+ // "he-IL" has non-breaking space in weekday names.
1059
+ return value.split( "\u00A0" ).join( " " ).toUpperCase();
1060
+ };
1061
+
1062
+ toUpperArray = function( arr ) {
1063
+ var results = [];
1064
+ for ( var i = 0, l = arr.length; i < l; i++ ) {
1065
+ results[ i ] = toUpper( arr[i] );
1066
+ }
1067
+ return results;
1068
+ };
1069
+
1070
+ parseExact = function( value, format, culture ) {
1071
+ // try to parse the date string by matching against the format string
1072
+ // while using the specified culture for date field names.
1073
+ value = trim( value );
1074
+ var cal = culture.calendar,
1075
+ // convert date formats into regular expressions with groupings.
1076
+ // use the regexp to determine the input format and extract the date fields.
1077
+ parseInfo = getParseRegExp( cal, format ),
1078
+ match = new RegExp( parseInfo.regExp ).exec( value );
1079
+ if ( match === null ) {
1080
+ return null;
1081
+ }
1082
+ // found a date format that matches the input.
1083
+ var groups = parseInfo.groups,
1084
+ era = null, year = null, month = null, date = null, weekDay = null,
1085
+ hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null,
1086
+ pmHour = false;
1087
+ // iterate the format groups to extract and set the date fields.
1088
+ for ( var j = 0, jl = groups.length; j < jl; j++ ) {
1089
+ var matchGroup = match[ j + 1 ];
1090
+ if ( matchGroup ) {
1091
+ var current = groups[ j ],
1092
+ clength = current.length,
1093
+ matchInt = parseInt( matchGroup, 10 );
1094
+ switch ( current ) {
1095
+ case "dd": case "d":
1096
+ // Day of month.
1097
+ date = matchInt;
1098
+ // check that date is generally in valid range, also checking overflow below.
1099
+ if ( outOfRange(date, 1, 31) ) return null;
1100
+ break;
1101
+ case "MMM": case "MMMM":
1102
+ month = getMonthIndex( cal, matchGroup, clength === 3 );
1103
+ if ( outOfRange(month, 0, 11) ) return null;
1104
+ break;
1105
+ case "M": case "MM":
1106
+ // Month.
1107
+ month = matchInt - 1;
1108
+ if ( outOfRange(month, 0, 11) ) return null;
1109
+ break;
1110
+ case "y": case "yy":
1111
+ case "yyyy":
1112
+ year = clength < 4 ? expandYear( cal, matchInt ) : matchInt;
1113
+ if ( outOfRange(year, 0, 9999) ) return null;
1114
+ break;
1115
+ case "h": case "hh":
1116
+ // Hours (12-hour clock).
1117
+ hour = matchInt;
1118
+ if ( hour === 12 ) hour = 0;
1119
+ if ( outOfRange(hour, 0, 11) ) return null;
1120
+ break;
1121
+ case "H": case "HH":
1122
+ // Hours (24-hour clock).
1123
+ hour = matchInt;
1124
+ if ( outOfRange(hour, 0, 23) ) return null;
1125
+ break;
1126
+ case "m": case "mm":
1127
+ // Minutes.
1128
+ min = matchInt;
1129
+ if ( outOfRange(min, 0, 59) ) return null;
1130
+ break;
1131
+ case "s": case "ss":
1132
+ // Seconds.
1133
+ sec = matchInt;
1134
+ if ( outOfRange(sec, 0, 59) ) return null;
1135
+ break;
1136
+ case "tt": case "t":
1137
+ // AM/PM designator.
1138
+ // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of
1139
+ // the AM tokens. If not, fail the parse for this format.
1140
+ pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] );
1141
+ if (
1142
+ !pmHour && (
1143
+ !cal.AM || ( matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2] )
1144
+ )
1145
+ ) return null;
1146
+ break;
1147
+ case "f":
1148
+ // Deciseconds.
1149
+ case "ff":
1150
+ // Centiseconds.
1151
+ case "fff":
1152
+ // Milliseconds.
1153
+ msec = matchInt * Math.pow( 10, 3 - clength );
1154
+ if ( outOfRange(msec, 0, 999) ) return null;
1155
+ break;
1156
+ case "ddd":
1157
+ // Day of week.
1158
+ case "dddd":
1159
+ // Day of week.
1160
+ weekDay = getDayIndex( cal, matchGroup, clength === 3 );
1161
+ if ( outOfRange(weekDay, 0, 6) ) return null;
1162
+ break;
1163
+ case "zzz":
1164
+ // Time zone offset in +/- hours:min.
1165
+ var offsets = matchGroup.split( /:/ );
1166
+ if ( offsets.length !== 2 ) return null;
1167
+ hourOffset = parseInt( offsets[0], 10 );
1168
+ if ( outOfRange(hourOffset, -12, 13) ) return null;
1169
+ var minOffset = parseInt( offsets[1], 10 );
1170
+ if ( outOfRange(minOffset, 0, 59) ) return null;
1171
+ tzMinOffset = ( hourOffset * 60 ) + ( startsWith(matchGroup, "-") ? -minOffset : minOffset );
1172
+ break;
1173
+ case "z": case "zz":
1174
+ // Time zone offset in +/- hours.
1175
+ hourOffset = matchInt;
1176
+ if ( outOfRange(hourOffset, -12, 13) ) return null;
1177
+ tzMinOffset = hourOffset * 60;
1178
+ break;
1179
+ case "g": case "gg":
1180
+ var eraName = matchGroup;
1181
+ if ( !eraName || !cal.eras ) return null;
1182
+ eraName = trim( eraName.toLowerCase() );
1183
+ for ( var i = 0, l = cal.eras.length; i < l; i++ ) {
1184
+ if ( eraName === cal.eras[i].name.toLowerCase() ) {
1185
+ era = i;
1186
+ break;
1187
+ }
1188
+ }
1189
+ // could not find an era with that name
1190
+ if ( era === null ) return null;
1191
+ break;
1192
+ }
1193
+ }
1194
+ }
1195
+ var result = new Date(), defaultYear, convert = cal.convert;
1196
+ defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear();
1197
+ if ( year === null ) {
1198
+ year = defaultYear;
1199
+ }
1200
+ else if ( cal.eras ) {
1201
+ // year must be shifted to normal gregorian year
1202
+ // but not if year was not specified, its already normal gregorian
1203
+ // per the main if clause above.
1204
+ year += cal.eras[( era || 0 )].offset;
1205
+ }
1206
+ // set default day and month to 1 and January, so if unspecified, these are the defaults
1207
+ // instead of the current day/month.
1208
+ if ( month === null ) {
1209
+ month = 0;
1210
+ }
1211
+ if ( date === null ) {
1212
+ date = 1;
1213
+ }
1214
+ // now have year, month, and date, but in the culture's calendar.
1215
+ // convert to gregorian if necessary
1216
+ if ( convert ) {
1217
+ result = convert.toGregorian( year, month, date );
1218
+ // conversion failed, must be an invalid match
1219
+ if ( result === null ) return null;
1220
+ }
1221
+ else {
1222
+ // have to set year, month and date together to avoid overflow based on current date.
1223
+ result.setFullYear( year, month, date );
1224
+ // check to see if date overflowed for specified month (only checked 1-31 above).
1225
+ if ( result.getDate() !== date ) return null;
1226
+ // invalid day of week.
1227
+ if ( weekDay !== null && result.getDay() !== weekDay ) {
1228
+ return null;
1229
+ }
1230
+ }
1231
+ // if pm designator token was found make sure the hours fit the 24-hour clock.
1232
+ if ( pmHour && hour < 12 ) {
1233
+ hour += 12;
1234
+ }
1235
+ result.setHours( hour, min, sec, msec );
1236
+ if ( tzMinOffset !== null ) {
1237
+ // adjust timezone to utc before applying local offset.
1238
+ var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() );
1239
+ // Safari limits hours and minutes to the range of -127 to 127. We need to use setHours
1240
+ // to ensure both these fields will not exceed this range. adjustedMin will range
1241
+ // somewhere between -1440 and 1500, so we only need to split this into hours.
1242
+ result.setHours( result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60 );
1243
+ }
1244
+ return result;
1245
+ };
1246
+ }());
1247
+
1248
+ parseNegativePattern = function( value, nf, negativePattern ) {
1249
+ var neg = nf[ "-" ],
1250
+ pos = nf[ "+" ],
1251
+ ret;
1252
+ switch ( negativePattern ) {
1253
+ case "n -":
1254
+ neg = " " + neg;
1255
+ pos = " " + pos;
1256
+ /* falls through */
1257
+ case "n-":
1258
+ if ( endsWith(value, neg) ) {
1259
+ ret = [ "-", value.substr(0, value.length - neg.length) ];
1260
+ }
1261
+ else if ( endsWith(value, pos) ) {
1262
+ ret = [ "+", value.substr(0, value.length - pos.length) ];
1263
+ }
1264
+ break;
1265
+ case "- n":
1266
+ neg += " ";
1267
+ pos += " ";
1268
+ /* falls through */
1269
+ case "-n":
1270
+ if ( startsWith(value, neg) ) {
1271
+ ret = [ "-", value.substr(neg.length) ];
1272
+ }
1273
+ else if ( startsWith(value, pos) ) {
1274
+ ret = [ "+", value.substr(pos.length) ];
1275
+ }
1276
+ break;
1277
+ case "(n)":
1278
+ if ( startsWith(value, "(") && endsWith(value, ")") ) {
1279
+ ret = [ "-", value.substr(1, value.length - 2) ];
1280
+ }
1281
+ break;
1282
+ }
1283
+ return ret || [ "", value ];
1284
+ };
1285
+
1286
+ //
1287
+ // public instance functions
1288
+ //
1289
+
1290
+ Globalize.prototype.findClosestCulture = function( cultureSelector ) {
1291
+ return Globalize.findClosestCulture.call( this, cultureSelector );
1292
+ };
1293
+
1294
+ Globalize.prototype.format = function( value, format, cultureSelector ) {
1295
+ return Globalize.format.call( this, value, format, cultureSelector );
1296
+ };
1297
+
1298
+ Globalize.prototype.localize = function( key, cultureSelector ) {
1299
+ return Globalize.localize.call( this, key, cultureSelector );
1300
+ };
1301
+
1302
+ Globalize.prototype.parseInt = function( value, radix, cultureSelector ) {
1303
+ return Globalize.parseInt.call( this, value, radix, cultureSelector );
1304
+ };
1305
+
1306
+ Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) {
1307
+ return Globalize.parseFloat.call( this, value, radix, cultureSelector );
1308
+ };
1309
+
1310
+ Globalize.prototype.culture = function( cultureSelector ) {
1311
+ return Globalize.culture.call( this, cultureSelector );
1312
+ };
1313
+
1314
+ //
1315
+ // public singleton functions
1316
+ //
1317
+
1318
+ Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) {
1319
+
1320
+ var base = {},
1321
+ isNew = false;
1322
+
1323
+ if ( typeof cultureName !== "string" ) {
1324
+ // cultureName argument is optional string. If not specified, assume info is first
1325
+ // and only argument. Specified info deep-extends current culture.
1326
+ info = cultureName;
1327
+ cultureName = this.culture().name;
1328
+ base = this.cultures[ cultureName ];
1329
+ } else if ( typeof baseCultureName !== "string" ) {
1330
+ // baseCultureName argument is optional string. If not specified, assume info is second
1331
+ // argument. Specified info deep-extends specified culture.
1332
+ // If specified culture does not exist, create by deep-extending default
1333
+ info = baseCultureName;
1334
+ isNew = ( this.cultures[ cultureName ] == null );
1335
+ base = this.cultures[ cultureName ] || this.cultures[ "default" ];
1336
+ } else {
1337
+ // cultureName and baseCultureName specified. Assume a new culture is being created
1338
+ // by deep-extending an specified base culture
1339
+ isNew = true;
1340
+ base = this.cultures[ baseCultureName ];
1341
+ }
1342
+
1343
+ this.cultures[ cultureName ] = extend(true, {},
1344
+ base,
1345
+ info
1346
+ );
1347
+ // Make the standard calendar the current culture if it's a new culture
1348
+ if ( isNew ) {
1349
+ this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard;
1350
+ }
1351
+ };
1352
+
1353
+ Globalize.findClosestCulture = function( name ) {
1354
+ var match;
1355
+ if ( !name ) {
1356
+ return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ];
1357
+ }
1358
+ if ( typeof name === "string" ) {
1359
+ name = name.split( "," );
1360
+ }
1361
+ if ( isArray(name) ) {
1362
+ var lang,
1363
+ cultures = this.cultures,
1364
+ list = name,
1365
+ i, l = list.length,
1366
+ prioritized = [];
1367
+ for ( i = 0; i < l; i++ ) {
1368
+ name = trim( list[i] );
1369
+ var pri, parts = name.split( ";" );
1370
+ lang = trim( parts[0] );
1371
+ if ( parts.length === 1 ) {
1372
+ pri = 1;
1373
+ }
1374
+ else {
1375
+ name = trim( parts[1] );
1376
+ if ( name.indexOf("q=") === 0 ) {
1377
+ name = name.substr( 2 );
1378
+ pri = parseFloat( name );
1379
+ pri = isNaN( pri ) ? 0 : pri;
1380
+ }
1381
+ else {
1382
+ pri = 1;
1383
+ }
1384
+ }
1385
+ prioritized.push({ lang: lang, pri: pri });
1386
+ }
1387
+ prioritized.sort(function( a, b ) {
1388
+ if ( a.pri < b.pri ) {
1389
+ return 1;
1390
+ } else if ( a.pri > b.pri ) {
1391
+ return -1;
1392
+ }
1393
+ return 0;
1394
+ });
1395
+ // exact match
1396
+ for ( i = 0; i < l; i++ ) {
1397
+ lang = prioritized[ i ].lang;
1398
+ match = cultures[ lang ];
1399
+ if ( match ) {
1400
+ return match;
1401
+ }
1402
+ }
1403
+
1404
+ // neutral language match
1405
+ for ( i = 0; i < l; i++ ) {
1406
+ lang = prioritized[ i ].lang;
1407
+ do {
1408
+ var index = lang.lastIndexOf( "-" );
1409
+ if ( index === -1 ) {
1410
+ break;
1411
+ }
1412
+ // strip off the last part. e.g. en-US => en
1413
+ lang = lang.substr( 0, index );
1414
+ match = cultures[ lang ];
1415
+ if ( match ) {
1416
+ return match;
1417
+ }
1418
+ }
1419
+ while ( 1 );
1420
+ }
1421
+
1422
+ // last resort: match first culture using that language
1423
+ for ( i = 0; i < l; i++ ) {
1424
+ lang = prioritized[ i ].lang;
1425
+ for ( var cultureKey in cultures ) {
1426
+ var culture = cultures[ cultureKey ];
1427
+ if ( culture.language == lang ) {
1428
+ return culture;
1429
+ }
1430
+ }
1431
+ }
1432
+ }
1433
+ else if ( typeof name === "object" ) {
1434
+ return name;
1435
+ }
1436
+ return match || null;
1437
+ };
1438
+
1439
+ Globalize.format = function( value, format, cultureSelector ) {
1440
+ var culture = this.findClosestCulture( cultureSelector );
1441
+ if ( value instanceof Date ) {
1442
+ value = formatDate( value, format, culture );
1443
+ }
1444
+ else if ( typeof value === "number" ) {
1445
+ value = formatNumber( value, format, culture );
1446
+ }
1447
+ return value;
1448
+ };
1449
+
1450
+ Globalize.localize = function( key, cultureSelector ) {
1451
+ return this.findClosestCulture( cultureSelector ).messages[ key ] ||
1452
+ this.cultures[ "default" ].messages[ key ];
1453
+ };
1454
+
1455
+ Globalize.parseDate = function( value, formats, culture ) {
1456
+ culture = this.findClosestCulture( culture );
1457
+
1458
+ var date, prop, patterns;
1459
+ if ( formats ) {
1460
+ if ( typeof formats === "string" ) {
1461
+ formats = [ formats ];
1462
+ }
1463
+ if ( formats.length ) {
1464
+ for ( var i = 0, l = formats.length; i < l; i++ ) {
1465
+ var format = formats[ i ];
1466
+ if ( format ) {
1467
+ date = parseExact( value, format, culture );
1468
+ if ( date ) {
1469
+ break;
1470
+ }
1471
+ }
1472
+ }
1473
+ }
1474
+ } else {
1475
+ patterns = culture.calendar.patterns;
1476
+ for ( prop in patterns ) {
1477
+ date = parseExact( value, patterns[prop], culture );
1478
+ if ( date ) {
1479
+ break;
1480
+ }
1481
+ }
1482
+ }
1483
+
1484
+ return date || null;
1485
+ };
1486
+
1487
+ Globalize.parseInt = function( value, radix, cultureSelector ) {
1488
+ return truncate( Globalize.parseFloat(value, radix, cultureSelector) );
1489
+ };
1490
+
1491
+ Globalize.parseFloat = function( value, radix, cultureSelector ) {
1492
+ // radix argument is optional
1493
+ if ( typeof radix !== "number" ) {
1494
+ cultureSelector = radix;
1495
+ radix = 10;
1496
+ }
1497
+
1498
+ var culture = this.findClosestCulture( cultureSelector );
1499
+ var ret = NaN,
1500
+ nf = culture.numberFormat;
1501
+
1502
+ if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) {
1503
+ // remove currency symbol
1504
+ value = value.replace( culture.numberFormat.currency.symbol, "" );
1505
+ // replace decimal seperator
1506
+ value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] );
1507
+ }
1508
+
1509
+ //Remove percentage character from number string before parsing
1510
+ if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){
1511
+ value = value.replace( culture.numberFormat.percent.symbol, "" );
1512
+ }
1513
+
1514
+ // remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR
1515
+ value = value.replace( / /g, "" );
1516
+
1517
+ // allow infinity or hexidecimal
1518
+ if ( regexInfinity.test(value) ) {
1519
+ ret = parseFloat( value );
1520
+ }
1521
+ else if ( !radix && regexHex.test(value) ) {
1522
+ ret = parseInt( value, 16 );
1523
+ }
1524
+ else {
1525
+
1526
+ // determine sign and number
1527
+ var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
1528
+ sign = signInfo[ 0 ],
1529
+ num = signInfo[ 1 ];
1530
+
1531
+ // #44 - try parsing as "(n)"
1532
+ if ( sign === "" && nf.pattern[0] !== "(n)" ) {
1533
+ signInfo = parseNegativePattern( value, nf, "(n)" );
1534
+ sign = signInfo[ 0 ];
1535
+ num = signInfo[ 1 ];
1536
+ }
1537
+
1538
+ // try parsing as "-n"
1539
+ if ( sign === "" && nf.pattern[0] !== "-n" ) {
1540
+ signInfo = parseNegativePattern( value, nf, "-n" );
1541
+ sign = signInfo[ 0 ];
1542
+ num = signInfo[ 1 ];
1543
+ }
1544
+
1545
+ sign = sign || "+";
1546
+
1547
+ // determine exponent and number
1548
+ var exponent,
1549
+ intAndFraction,
1550
+ exponentPos = num.indexOf( "e" );
1551
+ if ( exponentPos < 0 ) exponentPos = num.indexOf( "E" );
1552
+ if ( exponentPos < 0 ) {
1553
+ intAndFraction = num;
1554
+ exponent = null;
1555
+ }
1556
+ else {
1557
+ intAndFraction = num.substr( 0, exponentPos );
1558
+ exponent = num.substr( exponentPos + 1 );
1559
+ }
1560
+ // determine decimal position
1561
+ var integer,
1562
+ fraction,
1563
+ decSep = nf[ "." ],
1564
+ decimalPos = intAndFraction.indexOf( decSep );
1565
+ if ( decimalPos < 0 ) {
1566
+ integer = intAndFraction;
1567
+ fraction = null;
1568
+ }
1569
+ else {
1570
+ integer = intAndFraction.substr( 0, decimalPos );
1571
+ fraction = intAndFraction.substr( decimalPos + decSep.length );
1572
+ }
1573
+ // handle groups (e.g. 1,000,000)
1574
+ var groupSep = nf[ "," ];
1575
+ integer = integer.split( groupSep ).join( "" );
1576
+ var altGroupSep = groupSep.replace( /\u00A0/g, " " );
1577
+ if ( groupSep !== altGroupSep ) {
1578
+ integer = integer.split( altGroupSep ).join( "" );
1579
+ }
1580
+ // build a natively parsable number string
1581
+ var p = sign + integer;
1582
+ if ( fraction !== null ) {
1583
+ p += "." + fraction;
1584
+ }
1585
+ if ( exponent !== null ) {
1586
+ // exponent itself may have a number patternd
1587
+ var expSignInfo = parseNegativePattern( exponent, nf, "-n" );
1588
+ p += "e" + ( expSignInfo[0] || "+" ) + expSignInfo[ 1 ];
1589
+ }
1590
+ if ( regexParseFloat.test(p) ) {
1591
+ ret = parseFloat( p );
1592
+ }
1593
+ }
1594
+ return ret;
1595
+ };
1596
+
1597
+ Globalize.culture = function( cultureSelector ) {
1598
+ // setter
1599
+ if ( typeof cultureSelector !== "undefined" ) {
1600
+ this.cultureSelector = cultureSelector;
1601
+ }
1602
+ // getter
1603
+ return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ];
1604
+ };
1605
+
1606
+ document.Globalize = Globalize;
1607
1607
  }(this));