www/jqwidgets/globalization/globalize.js

changeset 368
e9dafd7a59d5
parent 1
37f1a08315f3
equal deleted inserted replaced
367:003f67218a49 368:e9dafd7a59d5
1 /* tslint:disable */
2 /* eslint-disable */
1 /*! 3 /*!
2 * Globalize 4 * Globalize
3 * 5 *
4 * http://github.com/jquery/globalize 6 * http://github.com/jquery/globalize
5 * 7 *
6 * Copyright Software Freedom Conservancy, Inc. 8 * Copyright Software Freedom Conservancy, Inc.
7 * Dual licensed under the MIT or GPL Version 2 licenses. 9 * Dual licensed under the MIT or GPL Version 2 licenses.
8 * http://jquery.org/license 10 * http://jquery.org/license
9 */ 11 */
10 (function(j,g){if(document.Globalize){return}var r,w,l,x,p,v,u,t,m,a,k,y,q,c,n,s,z,o,i,h,d,f,e,b;r=function(A){return new r.prototype.init(A)};if(typeof require!=="undefined"&&typeof exports!=="undefined"&&typeof module!=="undefined"){module.exports=r}else{j.Globalize=r}r.cultures={};r.prototype={constructor:r,init:function(A){this.cultures=r.cultures;this.cultureSelector=A;return this}};r.prototype.init.prototype=r.prototype;r.cultures["default"]={name:"en",englishName:"English",nativeName:"English",isRTL:false,language:"en",numberFormat:{pattern:["-n"],decimals:2,",":",",".":".",groupSizes:[3],"+":"+","-":"-","NaN":"NaN",negativeInfinity:"-Infinity",positiveInfinity:"Infinity",percent:{pattern:["-n %","n %"],decimals:2,groupSizes:[3],",":",",".":".",symbol:"%"},currency:{pattern:["($n)","$n"],decimals:2,groupSizes:[3],",":",",".":".",symbol:"$"}},calendars:{standard:{name:"Gregorian_USEnglish","/":"/",":":":",firstDay:0,days:{names:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],namesAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],namesShort:["Su","Mo","Tu","We","Th","Fr","Sa"]},months:{names:["January","February","March","April","May","June","July","August","September","October","November","December",""],namesAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""]},AM:["AM","am","AM"],PM:["PM","pm","PM"],eras:[{name:"A.D.",start:null,offset:0}],twoDigitYearMax:2029,patterns:{d:"M/d/yyyy",D:"dddd, MMMM dd, yyyy",t:"h:mm tt",T:"h:mm:ss tt",f:"dddd, MMMM dd, yyyy h:mm tt",F:"dddd, MMMM dd, yyyy h:mm:ss tt",M:"MMMM dd",Y:"yyyy MMMM",S:"yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss"}}},messages:{}};r.cultures["default"].calendar=r.cultures["default"].calendars.standard;r.cultures.en=r.cultures["default"];r.cultureSelector="en";w=/^0x[a-f0-9]+$/i;l=/^[+\-]?infinity$/i;x=/^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/;p=/^\s+|\s+$/g;v=function(D,C){if(D.indexOf){return D.indexOf(C)}for(var A=0,B=D.length;A<B;A++){if(D[A]===C){return A}}return -1};u=function(B,A){return B.substr(B.length-A.length)===A};t=function(){var J,C,A,B,G,H,F=arguments[0]||{},E=1,D=arguments.length,I=false;if(typeof F==="boolean"){I=F;F=arguments[1]||{};E=2}if(typeof F!=="object"&&!a(F)){F={}}for(;E<D;E++){if((J=arguments[E])!=null){for(C in J){A=F[C];B=J[C];if(F===B){continue}if(I&&B&&(k(B)||(G=m(B)))){if(G){G=false;H=A&&m(A)?A:[]}else{H=A&&k(A)?A:{}}F[C]=t(I,H,B)}else{if(B!==g){F[C]=B}}}}}return F};m=Array.isArray||function(A){return Object.prototype.toString.call(A)==="[object Array]"};a=function(A){return Object.prototype.toString.call(A)==="[object Function]"};k=function(A){return Object.prototype.toString.call(A)==="[object Object]"};y=function(B,A){return B.indexOf(A)===0};q=function(A){return(A+"").replace(p,"")};c=function(A){if(isNaN(A)){return NaN}return Math[A<0?"ceil":"floor"](A)};n=function(D,B,C){var A;for(A=D.length;A<B;A+=1){D=(C?("0"+D):(D+"0"))}return D};s=function(D,A){var C=0,F=false;for(var E=0,B=D.length;E<B;E++){var G=D.charAt(E);switch(G){case"'":if(F){A.push("'")}else{C++}F=false;break;case"\\":if(F){A.push("\\")}F=!F;break;default:A.push(G);F=false;break}}return C};z=function(E,D){D=D||"F";var C,B=E.patterns,A=D.length;if(A===1){C=B[D];if(!C){throw"Invalid date format string '"+D+"'."}D=C}else{if(A===2&&D.charAt(0)==="%"){D=D.charAt(1)}}return D};o=function(U,Y,Z){var M=Z.calendar,I=M.convert,ab;if(!Y||!Y.length||Y==="i"){if(Z&&Z.name.length){if(I){ab=o(U,M.patterns.F,Z)}else{var J=new Date(U.getTime()),Q=d(U,M.eras);J.setFullYear(f(U,M,Q));ab=J.toLocaleString()}}else{ab=U.toString()}return ab}var V=M.eras,B=Y==="s";Y=z(M,Y);ab=[];var F,W=["0","00","000"],K,L,A=/([^d]|^)(d|dd)([^d]|$)/g,aa=0,R=h(),C;function H(ac,af){if(ac<0){return"-"+H(-ac,af)}var ae,ad=ac+"";if(af>1&&ad.length<af){ae=(W[af-2]+ad);return ae.substr(ae.length-af,af)}else{ae=ad}return ae}function X(){if(K||L){return K}K=A.test(Y);L=true;return K}function D(ad,ac){if(C){return C[ac]}switch(ac){case 0:return ad.getFullYear();case 1:return ad.getMonth();case 2:return ad.getDate();default:throw"Invalid part value "+ac}}if(!B&&I){C=I.fromGregorian(U)}for(;;){var G=R.lastIndex,P=R.exec(Y);var N=Y.slice(G,P?P.index:Y.length);aa+=s(N,ab);if(!P){break}if(aa%2){ab.push(P[0]);continue}var S=P[0],E=S.length;switch(S){case"ddd":case"dddd":var O=(E===3)?M.days.namesAbbr:M.days.names;ab.push(O[U.getDay()]);break;case"d":case"dd":K=true;ab.push(H(D(U,2),E));break;case"MMM":case"MMMM":var T=D(U,1);ab.push((M.monthsGenitive&&X())?(M.monthsGenitive[E===3?"namesAbbr":"names"][T]):(M.months[E===3?"namesAbbr":"names"][T]));break;case"M":case"MM":ab.push(H(D(U,1)+1,E));break;case"y":case"yy":case"yyyy":T=C?C[0]:f(U,M,d(U,V),B);if(E<4){T=T%100}ab.push(H(T,E));break;case"h":case"hh":F=U.getHours()%12;if(F===0){F=12}ab.push(H(F,E));break;case"H":case"HH":ab.push(H(U.getHours(),E));break;case"m":case"mm":ab.push(H(U.getMinutes(),E));break;case"s":case"ss":ab.push(H(U.getSeconds(),E));break;case"t":case"tt":T=U.getHours()<12?(M.AM?M.AM[0]:" "):(M.PM?M.PM[0]:" ");ab.push(E===1?T.charAt(0):T);break;case"f":case"ff":case"fff":ab.push(H(U.getMilliseconds(),3).substr(0,E));break;case"z":case"zz":F=U.getTimezoneOffset()/60;ab.push((F<=0?"+":"-")+H(Math.floor(Math.abs(F)),E));break;case"zzz":F=U.getTimezoneOffset()/60;ab.push((F<=0?"+":"-")+H(Math.floor(Math.abs(F)),2)+":"+H(Math.abs(U.getTimezoneOffset()%60),2));break;case"g":case"gg":if(M.eras){ab.push(M.eras[d(U,V)].name)}break;case"/":ab.push(M["/"]);break;default:throw"Invalid date format pattern '"+S+"'."}}return ab.join("")};(function(){var A;A=function(H,I,P){var F=P.groupSizes,B=F[0],C=1,M=Math.pow(10,I),D=Math.round(H*M)/M;if(!isFinite(D)){D=H}H=D;var G=H+"",O="",L=G.split(/e/i),N=L.length>1?parseInt(L[1],10):0;G=L[0];L=G.split(".");G=L[0];O=L.length>1?L[1]:"";var E;if(N>0){O=n(O,N,false);G+=O.slice(0,N);O=O.substr(N)}else{if(N<0){N=-N;G=n(G,N+1,true);O=G.slice(-N,G.length)+O;G=G.slice(0,-N)}}if(I>0){O=P["."]+((O.length>I)?O.slice(0,I):n(O,I))}else{O=""}var K=G.length-1,Q=P[","],J="";while(K>=0){if(B===0||B>K){return G.slice(0,K+1)+(J.length?(Q+J+O):O)}J=G.slice(K-B+1,K+1)+(J.length?(Q+J):"");K-=B;if(C<F.length){B=F[C];C++}}return G.slice(0,K+1)+Q+J+O};i=function(M,L,F){if(!isFinite(M)){if(M===Infinity){return F.numberFormat.positiveInfinity}if(M===-Infinity){return F.numberFormat.negativeInfinity}return F.numberFormat.NaN}if(!L||L==="i"){return F.name.length?M.toLocaleString():M.toString()}L=L||"D";var D=F.numberFormat,E=Math.abs(M),G=-1,K;if(L.length>1){G=parseInt(L.slice(1),10)}var J=L.charAt(0).toUpperCase(),N;switch(J){case"D":K="n";E=c(E);if(G!==-1){E=n(""+E,G,true)}if(M<0){E="-"+E}break;case"N":N=D;case"C":N=N||D.currency;case"P":N=N||D.percent;K=M<0?N.pattern[0]:(N.pattern[1]||"n");if(G===-1){G=N.decimals}E=A(E*(J==="P"?100:1),G,N);break;default:throw"Bad number format specifier: "+J}var B=/n|\$|-|%/g,I="";for(;;){var H=B.lastIndex,C=B.exec(K);I+=K.slice(H,C?C.index:K.length);if(!C){break}switch(C[0]){case"n":I+=E;break;case"$":I+=D.currency.symbol;break;case"-":if(/[1-9]/.test(E)){I+=D["-"]}break;case"%":I+=D.percent.symbol;break}}return I}}());h=function(){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)};d=function(C,B){if(!B){return 0}var F,E=C.getTime();for(var D=0,A=B.length;D<A;D++){F=B[D].start;if(F===null||E>=F){return D}}return 0};f=function(B,D,A,E){var C=B.getFullYear();if(!E&&D.eras){C-=D.eras[A].offset}return C};(function(){var B,A,D,C,G,F,E;B=function(M,K){if(K<100){var I=new Date(),H=d(I),L=f(I,M,H),J=M.twoDigitYearMax;J=typeof J==="string"?new Date().getFullYear()%100+parseInt(J,10):J;K+=L-(L%100);if(K>J){K-=100}}return K};A=function(L,K,I){var H,M=L.days,J=L._upperDays;if(!J){L._upperDays=J=[E(M.names),E(M.namesAbbr),E(M.namesShort)]}K=F(K);if(I){H=v(J[1],K);if(H===-1){H=v(J[2],K)}}else{H=v(J[0],K)}return H};D=function(O,N,J){var H=O.months,I=O.monthsGenitive||O.months,L=O._upperMonths,M=O._upperMonthsGen;if(!L){O._upperMonths=L=[E(H.names),E(H.namesAbbr)];O._upperMonthsGen=M=[E(I.names),E(I.namesAbbr)]}N=F(N);var K=v(J?L[1]:L[0],N);if(K<0){K=v(J?M[1]:M[0],N)}return K};C=function(H,S){var U=H._parseRegExp;if(!U){H._parseRegExp=U={}}else{var L=U[S];if(L){return L}}var R=z(H,S).replace(/([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g,"\\\\$1"),P=["^"],I=[],O=0,K=0,X=h(),M;while((M=X.exec(R))!==null){var W=R.slice(O,M.index);O=X.lastIndex;K+=s(W,P);if(K%2){P.push(M[0]);continue}var J=M[0],N=J.length,T;switch(J){case"dddd":case"ddd":case"MMMM":case"MMM":case"gg":case"g":T="(\\D+)";break;case"tt":case"t":T="(\\D*)";break;case"yyyy":case"fff":case"ff":case"f":T="(\\d{"+N+"})";break;case"dd":case"d":case"MM":case"M":case"yy":case"y":case"HH":case"H":case"hh":case"h":case"mm":case"m":case"ss":case"s":T="(\\d\\d?)";break;case"zzz":T="([+-]?\\d\\d?:\\d{2})";break;case"zz":case"z":T="([+-]?\\d\\d?)";break;case"/":T="(\\/)";break;default:throw"Invalid date format pattern '"+J+"'."}if(T){P.push(T)}I.push(M[0])}s(R.slice(O),P);P.push("$");var V=P.join("").replace(/\s+/g,"\\s+"),Q={regExp:V,groups:I};return U[S]=Q};G=function(J,H,I){return J<H||J>I};F=function(H){return H.split("\u00A0").join(" ").toUpperCase()};E=function(H){var K=[];for(var J=0,I=H.length;J<I;J++){K[J]=F(H[J])}return K};e=function(ab,ai,aj){ab=q(ab);var U=aj.calendar,ao=C(U,ai),O=new RegExp(ao.regExp).exec(ab);if(O===null){return null}var ak=ao.groups,Z=null,S=null,an=null,am=null,T=null,M=0,ae,ad=0,al=0,H=0,J=null,V=false;for(var af=0,ah=ak.length;af<ah;af++){var I=O[af+1];if(I){var aa=ak[af],L=aa.length,N=parseInt(I,10);switch(aa){case"dd":case"d":am=N;if(G(am,1,31)){return null}break;case"MMM":case"MMMM":an=D(U,I,L===3);if(G(an,0,11)){return null}break;case"M":case"MM":an=N-1;if(G(an,0,11)){return null}break;case"y":case"yy":case"yyyy":S=L<4?B(U,N):N;if(G(S,0,9999)){return null}break;case"h":case"hh":M=N;if(M===12){M=0}if(G(M,0,11)){return null}break;case"H":case"HH":M=N;if(G(M,0,23)){return null}break;case"m":case"mm":ad=N;if(G(ad,0,59)){return null}break;case"s":case"ss":al=N;if(G(al,0,59)){return null}break;case"tt":case"t":V=U.PM&&(I===U.PM[0]||I===U.PM[1]||I===U.PM[2]);if(!V&&(!U.AM||(I!==U.AM[0]&&I!==U.AM[1]&&I!==U.AM[2]))){return null}break;case"f":case"ff":case"fff":H=N*Math.pow(10,3-L);if(G(H,0,999)){return null}break;case"ddd":case"dddd":T=A(U,I,L===3);if(G(T,0,6)){return null}break;case"zzz":var K=I.split(/:/);if(K.length!==2){return null}ae=parseInt(K[0],10);if(G(ae,-12,13)){return null}var Q=parseInt(K[1],10);if(G(Q,0,59)){return null}J=(ae*60)+(y(I,"-")?-Q:Q);break;case"z":case"zz":ae=N;if(G(ae,-12,13)){return null}J=ae*60;break;case"g":case"gg":var W=I;if(!W||!U.eras){return null}W=q(W.toLowerCase());for(var ag=0,ac=U.eras.length;ag<ac;ag++){if(W===U.eras[ag].name.toLowerCase()){Z=ag;break}}if(Z===null){return null}break}}}var R=new Date(),Y,P=U.convert;Y=P?P.fromGregorian(R)[0]:R.getFullYear();if(S===null){S=Y}else{if(U.eras){S+=U.eras[(Z||0)].offset}}if(an===null){an=0}if(am===null){am=1}if(P){R=P.toGregorian(S,an,am);if(R===null){return null}}else{R.setFullYear(S,an,am);if(R.getDate()!==am){return null}if(T!==null&&R.getDay()!==T){return null}}if(V&&M<12){M+=12}R.setHours(M,ad,al,H);if(J!==null){var X=R.getMinutes()-(J+R.getTimezoneOffset());R.setHours(R.getHours()+parseInt(X/60,10),X%60)}return R}}());b=function(D,C,B){var F=C["-"],E=C["+"],A;switch(B){case"n -":F=" "+F;E=" "+E;case"n-":if(u(D,F)){A=["-",D.substr(0,D.length-F.length)]}else{if(u(D,E)){A=["+",D.substr(0,D.length-E.length)]}}break;case"- n":F+=" ";E+=" ";case"-n":if(y(D,F)){A=["-",D.substr(F.length)]}else{if(y(D,E)){A=["+",D.substr(E.length)]}}break;case"(n)":if(y(D,"(")&&u(D,")")){A=["-",D.substr(1,D.length-2)]}break}return A||["",D]};r.prototype.findClosestCulture=function(A){return r.findClosestCulture.call(this,A)};r.prototype.format=function(A,B,C){return r.format.call(this,A,B,C)};r.prototype.localize=function(A,B){return r.localize.call(this,A,B)};r.prototype.parseInt=function(B,A,C){return r.parseInt.call(this,B,A,C)};r.prototype.parseFloat=function(B,A,C){return r.parseFloat.call(this,B,A,C)};r.prototype.culture=function(A){return r.culture.call(this,A)};r.addCultureInfo=function(E,B,D){var C={},A=false;if(typeof E!=="string"){D=E;E=this.culture().name;C=this.cultures[E]}else{if(typeof B!=="string"){D=B;A=(this.cultures[E]==null);C=this.cultures[E]||this.cultures["default"]}else{A=true;C=this.cultures[B]}}this.cultures[E]=t(true,{},C,D);if(A){this.cultures[E].calendar=this.cultures[E].calendars.standard}};r.findClosestCulture=function(A){var I;if(!A){return this.findClosestCulture(this.cultureSelector)||this.cultures["default"]}if(typeof A==="string"){A=A.split(",")}if(m(A)){var C,M=this.cultures,K=A,H,D=K.length,L=[];for(H=0;H<D;H++){A=q(K[H]);var B,G=A.split(";");C=q(G[0]);if(G.length===1){B=1}else{A=q(G[1]);if(A.indexOf("q=")===0){A=A.substr(2);B=parseFloat(A);B=isNaN(B)?0:B}else{B=1}}L.push({lang:C,pri:B})}L.sort(function(O,N){if(O.pri<N.pri){return 1}else{if(O.pri>N.pri){return -1}}return 0});for(H=0;H<D;H++){C=L[H].lang;I=M[C];if(I){return I}}for(H=0;H<D;H++){C=L[H].lang;do{var J=C.lastIndexOf("-");if(J===-1){break}C=C.substr(0,J);I=M[C];if(I){return I}}while(1)}for(H=0;H<D;H++){C=L[H].lang;for(var F in M){var E=M[F];if(E.language==C){return E}}}}else{if(typeof A==="object"){return A}}return I||null};r.format=function(B,C,D){var A=this.findClosestCulture(D);if(B instanceof Date){B=o(B,C,A)}else{if(typeof B==="number"){B=i(B,C,A)}}return B};r.localize=function(A,B){return this.findClosestCulture(B).messages[A]||this.cultures["default"].messages[A]};r.parseDate=function(I,G,E){E=this.findClosestCulture(E);var C,A,B;if(G){if(typeof G==="string"){G=[G]}if(G.length){for(var F=0,D=G.length;F<D;F++){var H=G[F];if(H){C=e(I,H,E);if(C){break}}}}}else{B=E.calendar.patterns;for(A in B){C=e(I,B[A],E);if(C){break}}}return C||null};r.parseInt=function(B,A,C){return c(r.parseFloat(B,A,C))};r.parseFloat=function(O,H,J){if(typeof H!=="number"){J=H;H=10}var Q=this.findClosestCulture(J);var T=NaN,F=Q.numberFormat;if(O.indexOf(Q.numberFormat.currency.symbol)>-1){O=O.replace(Q.numberFormat.currency.symbol,"");O=O.replace(Q.numberFormat.currency["."],Q.numberFormat["."])}if(O.indexOf(Q.numberFormat.percent.symbol)>-1){O=O.replace(Q.numberFormat.percent.symbol,"")}O=O.replace(/ /g,"");if(l.test(O)){T=parseFloat(O)}else{if(!H&&w.test(O)){T=parseInt(O,16)}else{var C=b(O,F,F.pattern[0]),S=C[0],I=C[1];if(S===""&&F.pattern[0]!=="(n)"){C=b(O,F,"(n)");S=C[0];I=C[1]}if(S===""&&F.pattern[0]!=="-n"){C=b(O,F,"-n");S=C[0];I=C[1]}S=S||"+";var N,K,R=I.indexOf("e");if(R<0){R=I.indexOf("E")}if(R<0){K=I;N=null}else{K=I.substr(0,R);N=I.substr(R+1)}var P,G,D=F["."],A=K.indexOf(D);if(A<0){P=K;G=null}else{P=K.substr(0,A);G=K.substr(A+D.length)}var L=F[","];P=P.split(L).join("");var E=L.replace(/\u00A0/g," ");if(L!==E){P=P.split(E).join("")}var M=S+P;if(G!==null){M+="."+G}if(N!==null){var B=b(N,F,"-n");M+="e"+(B[0]||"+")+B[1]}if(x.test(M)){T=parseFloat(M)}}}return T};r.culture=function(A){if(typeof A!=="undefined"){this.cultureSelector=A}return this.findClosestCulture(A)||this.cultures["default"]};document.Globalize=r}(this)); 12
13 (function( window, undefined ) {
14 if (document.Globalize) {
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
504 function padZeros(num, c) {
505 if (num < 0) {
506 return "-" + padZeros(-num, c);
507 }
508 var r, s = num + "";
509 if (c > 1 && s.length < c) {
510 r = (zeros[c - 2] + s);
511 return r.substr(r.length - c, c);
512 }
513 else {
514 r = s;
515 }
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;
1607 }(this));

mercurial