yavsc/web/Scripts/globalize/number.js

1267 lines
33 KiB
JavaScript

Fixes bill editon * AppAdmin.master: A new master page for Administration * Web.config: * Web.csproj: * Book.aspx: * Auth.aspx: * Auth.aspx: * Book.aspx: * Auth.aspx: * TagPanel.ascx: * YavscModel.csproj: * Restore.aspx: * Book.aspx: * Restored.aspx: * date.js: * RoleList.aspx: * UserList.aspx: * LocalizedText.resx: * number.js: * FreeDate.cs: * plural.js: * message.js: * BookQuery.cs: * LocalizedText.fr.resx: * ChooseADate.aspx: * currency.js: * ChooseADate.aspx: * ErrorMessage.aspx: * globalize.js: * ChooseADate.aspx: * ChooseCalendar.aspx: * LocalizedText.Designer.cs: * ChooseCalendar.aspx: * ErrorMessage.aspx: * relative-time.js: * ChooseCalendar.aspx: * LocalizedText.fr.Designer.cs: * OtherWebException.aspx: * globalize.cultures.js: * globalize.culture.he.js: * globalize.culture.ru.js: * globalize.culture.ha.js: * globalize.culture.rw.js: * globalize.culture.gu.js: * globalize.culture.sa.js: * globalize.culture.gl.js: * globalize.culture.hi.js: * globalize.culture.pt.js: * globalize.culture.id.js: * globalize.culture.hy.js: * globalize.culture.hu.js: * globalize.culture.rm.js: * globalize.culture.hr.js: * globalize.culture.ro.js: * globalize.culture.gd.js: * globalize.culture.fi.js: * globalize.culture.fa.js: * globalize.culture.eu.js: * globalize.culture.et.js: * globalize.culture.es.js: * globalize.culture.sq.js: * globalize.culture.sr.js: * globalize.culture.sl.js: * globalize.culture.ga.js: * globalize.culture.fy.js: * globalize.culture.fr.js: * globalize.culture.se.js: * globalize.culture.si.js: * globalize.culture.sk.js: * globalize.culture.fo.js: * globalize.culture.ig.js: * globalize.culture.ml.js: * globalize.culture.mt.js: * globalize.culture.nl.js: * globalize.culture.ms.js: * globalize.culture.ky.js: * globalize.culture.mn.js: * globalize.culture.nn.js: * globalize.culture.mk.js: * globalize.culture.ne.js: * globalize.culture.lt.js: * globalize.culture.lv.js: * globalize.culture.lo.js: * globalize.culture.mi.js: * globalize.culture.lb.js: * globalize.culture.nb.js: * globalize.culture.ko.js: * globalize.culture.iu.js: * globalize.culture.pa.js: * globalize.culture.pl.js: * globalize.culture.it.js: * globalize.culture.ps.js: * globalize.culture.is.js: * globalize.culture.ii.js: * globalize.culture.ja.js: * globalize.culture.no.js: * globalize.culture.kn.js: * globalize.culture.km.js: * globalize.culture.kl.js: * globalize.culture.oc.js: * globalize.culture.kk.js: * globalize.culture.ka.js: * globalize.culture.or.js: * globalize.culture.sv.js: * globalize.culture.xh.js: * globalize.culture.dv.js: * globalize.culture.yo.js: * globalize.culture.de.js: * globalize.culture.da.js: * globalize.culture.zh.js: * globalize.culture.cy.js: * globalize.culture.el.js: * globalize.culture.tt.js: * globalize.culture.ug.js: * globalize.culture.uk.js: * globalize.culture.ur.js: * globalize.culture.uz.js: * globalize.culture.vi.js: * globalize.culture.wo.js: * globalize.culture.cs.js: * globalize.culture.be.js: * globalize.culture.ba.js: * globalize.culture.az.js: * globalize.culture.as.js: * globalize.culture.ar.js: * globalize.culture.am.js: * globalize.culture.af.js: * globalize.culture.bg.js: * globalize.culture.zu.js: * globalize.culture.co.js: * globalize.culture.ca.js: * globalize.culture.bs.js: * globalize.culture.br.js: * globalize.culture.bo.js: * globalize.culture.bn.js: * globalize.culture.mr.js: * globalize.culture.tn.js: * globalize.culture.sw.js: * globalize.culture.tg.js: * globalize.culture.ta.js: * globalize.culture.tr.js: * globalize.culture.te.js: * globalize.culture.th.js: * globalize.culture.tk.js: * globalize.culture.dsb.js: * globalize.culture.prs.js: * globalize.culture.quz.js: * globalize.culture.kok.js: * globalize.culture.smn.js: * globalize.culture.qut.js: * globalize.culture.sms.js: * globalize.culture.sma.js: * globalize.culture.sah.js: * globalize.culture.gsw.js: * globalize.culture.moh.js: * globalize.culture.tzm.js: * globalize.culture.nso.js: * globalize.culture.arn.js: * globalize.culture.hsb.js: * globalize.culture.syr.js: * globalize.culture.fil.js: * globalize.culture.smj.js: * globalize.culture.oc-FR.js: * globalize.culture.th-TH.js: * globalize.culture.zu-ZA.js: * globalize.culture.nn-NO.js: * globalize.culture.sw-KE.js: * globalize.culture.mt-MT.js: * globalize.culture.sv-FI.js: * globalize.culture.ms-MY.js: * globalize.culture.sv-SE.js: * globalize.culture.ms-BN.js: * globalize.culture.nb-NO.js: * globalize.culture.te-IN.js: * globalize.culture.nl-NL.js: * globalize.culture.nl-BE.js: * globalize.culture.ta-IN.js: * globalize.culture.ne-NP.js: * globalize.culture.sq-AL.js: * globalize.culture.sl-SI.js: * globalize.culture.ro-RO.js: * globalize.culture.se-NO.js: * globalize.culture.vi-VN.js: * globalize.culture.rm-CH.js: * globalize.culture.wo-SN.js: * globalize.culture.se-SE.js: * globalize.culture.xh-ZA.js: * globalize.culture.tr-TR.js: * globalize.culture.sa-IN.js: * globalize.culture.ug-CN.js: * globalize.culture.rw-RW.js: * globalize.culture.uk-UA.js: * globalize.culture.se-FI.js: * globalize.culture.ru-RU.js: * globalize.culture.ur-PK.js: * globalize.culture.tn-ZA.js: * globalize.culture.zh-CN.js: * globalize.culture.pa-IN.js: * globalize.culture.tt-RU.js: * globalize.culture.zh-MO.js: * globalize.culture.zh-SG.js: * globalize.culture.or-IN.js: * globalize.culture.zh-TW.js: * globalize.culture.sk-SK.js: * globalize.culture.pt-PT.js: * globalize.culture.pt-BR.js: * globalize.culture.si-LK.js: * globalize.culture.yo-NG.js: * globalize.culture.ps-AF.js: * globalize.culture.tk-TM.js: * globalize.culture.pl-PL.js: * globalize.culture.zh-HK.js: * globalize.culture.en-NZ.js: * globalize.culture.en-PH.js: * globalize.culture.en-SG.js: * globalize.culture.en-TT.js: * globalize.culture.en-US.js: * globalize.culture.en-ZA.js: * globalize.culture.en-ZW.js: * globalize.culture.es-AR.js: * globalize.culture.en-MY.js: * globalize.culture.el-GR.js: * globalize.culture.en-AU.js: * globalize.culture.en-BZ.js: * globalize.culture.en-CA.js: * globalize.culture.en-GB.js: * globalize.culture.en-IE.js: * globalize.culture.en-IN.js: * globalize.culture.en-JM.js: * globalize.culture.es-BO.js: * globalize.culture.es-NI.js: * globalize.culture.es-PA.js: * globalize.culture.es-PE.js: * globalize.culture.es-PR.js: * globalize.culture.es-PY.js: * globalize.culture.es-SV.js: * globalize.culture.es-US.js: * globalize.culture.es-UY.js: * globalize.culture.es-MX.js: * globalize.culture.es-CL.js: * globalize.culture.es-CO.js: * globalize.culture.es-CR.js: * globalize.culture.es-DO.js: * globalize.culture.es-EC.js: * globalize.culture.es-ES.js: * globalize.culture.es-GT.js: * globalize.culture.es-HN.js: * globalize.culture.dv-MV.js: * globalize.culture.ar-LY.js: * globalize.culture.ar-MA.js: * globalize.culture.ar-OM.js: * globalize.culture.ar-QA.js: * globalize.culture.ar-SA.js: * globalize.culture.ar-SY.js: * globalize.culture.ar-TN.js: * globalize.culture.ar-YE.js: * globalize.culture.ar-LB.js: * globalize.culture.am-ET.js: * globalize.culture.ar-AE.js: * globalize.culture.ar-BH.js: * globalize.culture.ar-DZ.js: * globalize.culture.ar-EG.js: * globalize.culture.ar-IQ.js: * globalize.culture.ar-JO.js: * globalize.culture.ar-KW.js: * globalize.culture.as-IN.js: * globalize.culture.cs-CZ.js: * globalize.culture.cy-GB.js: * globalize.culture.da-DK.js: * globalize.culture.de-AT.js: * globalize.culture.de-CH.js: * globalize.culture.de-DE.js: * globalize.culture.de-LI.js: * globalize.culture.de-LU.js: * globalize.culture.co-FR.js: * globalize.culture.ba-RU.js: * globalize.culture.be-BY.js: * globalize.culture.bg-BG.js: * globalize.culture.bn-BD.js: * globalize.culture.bn-IN.js: * globalize.culture.bo-CN.js: * globalize.culture.br-FR.js: * globalize.culture.ca-ES.js: * globalize.culture.es-VE.js: * globalize.culture.hy-AM.js: * globalize.culture.id-ID.js: * globalize.culture.ig-NG.js: * globalize.culture.ii-CN.js: * globalize.culture.is-IS.js: * globalize.culture.it-CH.js: * globalize.culture.it-IT.js: * globalize.culture.hu-HU.js: * globalize.culture.gd-GB.js: * globalize.culture.gl-ES.js: * globalize.culture.gu-IN.js: * globalize.culture.he-IL.js: * globalize.culture.hi-IN.js: * globalize.culture.hr-BA.js: * globalize.culture.hr-HR.js: * globalize.culture.ja-JP.js: * globalize.culture.lt-LT.js: * globalize.culture.af-ZA.js: * globalize.culture.mi-NZ.js: * globalize.culture.mk-MK.js: * globalize.culture.ml-IN.js: * globalize.culture.mn-MN.js: * globalize.culture.mr-IN.js: * globalize.culture.lo-LA.js: * globalize.culture.ka-GE.js: * globalize.culture.kk-KZ.js: * globalize.culture.kl-GL.js: * globalize.culture.km-KH.js: * globalize.culture.kn-IN.js: * globalize.culture.ko-KR.js: * globalize.culture.ky-KG.js: * globalize.culture.lb-LU.js: * globalize.culture.ga-IE.js: * globalize.culture.fr-CH.js: * globalize.culture.fr-CA.js: * globalize.culture.fr-BE.js: * globalize.culture.fo-FO.js: * globalize.culture.lv-LV.js: * globalize.culture.fi-FI.js: * globalize.culture.fa-IR.js: * globalize.culture.eu-ES.js: * globalize.culture.et-EE.js: * globalize.culture.fr-FR.js: * globalize.culture.fy-NL.js: * globalize.culture.fr-LU.js: * globalize.culture.fr-MC.js: * globalize.culture.sma-SE.js: * globalize.culture.sma-NO.js: * globalize.culture.arn-CL.js: * globalize.culture.qut-GT.js: * globalize.culture.gsw-FR.js: * globalize.culture.fil-PH.js: * globalize.culture.smj-SE.js: * globalize.culture.smn-FI.js: * globalize.culture.sah-RU.js: * globalize.culture.sms-FI.js: * globalize.culture.prs-AF.js: * globalize.culture.syr-SY.js: * globalize.culture.smj-NO.js: * globalize.culture.zh-CHT.js: * globalize.culture.kok-IN.js: * globalize.culture.hsb-DE.js: * globalize.culture.moh-CA.js: * globalize.culture.nso-ZA.js: * globalize.culture.quz-PE.js: * globalize.culture.zh-CHS.js: * globalize.culture.dsb-DE.js: * globalize.culture.quz-BO.js: * globalize.culture.quz-EC.js: * globalize.culture.en-029.js: * globalize.culture.mn-Mong.js: * globalize.culture.mn-Cyrl.js: * globalize.culture.sr-Cyrl.js: * globalize.culture.az-Latn.js: * globalize.culture.az-Cyrl.js: * globalize.culture.sr-Latn.js: * globalize.culture.iu-Latn.js: * globalize.culture.zh-Hant.js: * globalize.culture.zh-Hans.js: * globalize.culture.tg-Cyrl.js: * globalize.culture.uz-Latn.js: * globalize.culture.uz-Cyrl.js: * globalize.culture.ha-Latn.js: * globalize.culture.iu-Cans.js: * globalize.culture.bs-Cyrl.js: * globalize.culture.bs-Latn.js: * globalize.culture.tzm-Latn.js: * globalize.culture.sr-Cyrl-ME.js: * globalize.culture.sr-Cyrl-CS.js: * globalize.culture.bs-Cyrl-BA.js: * globalize.culture.sr-Cyrl-RS.js: * globalize.culture.sr-Cyrl-BA.js: * globalize.culture.mn-Mong-CN.js: * globalize.culture.uz-Cyrl-UZ.js: * globalize.culture.ha-Latn-NG.js: * globalize.culture.iu-Latn-CA.js: * globalize.culture.uz-Latn-UZ.js: * globalize.culture.az-Latn-AZ.js: * globalize.culture.az-Cyrl-AZ.js: * globalize.culture.bs-Latn-BA.js: * globalize.culture.tg-Cyrl-TJ.js: * globalize.culture.iu-Cans-CA.js: * globalize.culture.sr-Latn-RS.js: * globalize.culture.sr-Latn-ME.js: * globalize.culture.sr-Latn-CS.js: * globalize.culture.sr-Latn-BA.js: * globalize.culture.tzm-Latn-DZ.js: * style.css: list in the nav are in line by default. * AdminController.cs: refactoring * App.master: Restores hallo editing by solving again jQuery-ui ref * Login.aspx: Prettier code at building Urls * Admin.aspx: * Index.aspx: * AddRole.aspx: * Backups.aspx: * RemoveUser.aspx: * RemoveRole..aspx: * CreateBackup.aspx: * BackupCreated.aspx: new master page
9 years ago
/**
* Globalize v1.0.0
*
* http://github.com/jquery/globalize
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2015-04-23T12:02Z
*/
/*!
* Globalize v1.0.0 2015-04-23T12:02Z Released under the MIT license
* http://git.io/TrdQbw
*/
(function( root, factory ) {
// UMD returnExports
if ( typeof define === "function" && define.amd ) {
// AMD
define([
"cldr",
"../globalize",
"cldr/event",
"cldr/supplemental"
], factory );
} else if ( typeof exports === "object" ) {
// Node, CommonJS
module.exports = factory( require( "cldrjs" ), require( "globalize" ) );
} else {
// Global
factory( root.Cldr, root.Globalize );
}
}(this, function( Cldr, Globalize ) {
var createError = Globalize._createError,
objectExtend = Globalize._objectExtend,
regexpEscape = Globalize._regexpEscape,
stringPad = Globalize._stringPad,
validateCldr = Globalize._validateCldr,
validateDefaultLocale = Globalize._validateDefaultLocale,
validateParameterPresence = Globalize._validateParameterPresence,
validateParameterRange = Globalize._validateParameterRange,
validateParameterType = Globalize._validateParameterType,
validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
var createErrorUnsupportedFeature = function( feature ) {
return createError( "E_UNSUPPORTED", "Unsupported {feature}.", {
feature: feature
});
};
var validateParameterTypeNumber = function( value, name ) {
validateParameterType(
value,
name,
value === undefined || typeof value === "number",
"Number"
);
};
var validateParameterTypeString = function( value, name ) {
validateParameterType(
value,
name,
value === undefined || typeof value === "string",
"a string"
);
};
/**
* goupingSeparator( number, primaryGroupingSize, secondaryGroupingSize )
*
* @number [Number].
*
* @primaryGroupingSize [Number]
*
* @secondaryGroupingSize [Number]
*
* Return the formatted number with group separator.
*/
var numberFormatGroupingSeparator = function( number, primaryGroupingSize, secondaryGroupingSize ) {
var index,
currentGroupingSize = primaryGroupingSize,
ret = "",
sep = ",",
switchToSecondary = secondaryGroupingSize ? true : false;
number = String( number ).split( "." );
index = number[ 0 ].length;
while ( index > currentGroupingSize ) {
ret = number[ 0 ].slice( index - currentGroupingSize, index ) +
( ret.length ? sep : "" ) + ret;
index -= currentGroupingSize;
if ( switchToSecondary ) {
currentGroupingSize = secondaryGroupingSize;
switchToSecondary = false;
}
}
number[ 0 ] = number[ 0 ].slice( 0, index ) + ( ret.length ? sep : "" ) + ret;
return number.join( "." );
};
/**
* integerFractionDigits( number, minimumIntegerDigits, minimumFractionDigits,
* maximumFractionDigits, round, roundIncrement )
*
* @number [Number]
*
* @minimumIntegerDigits [Number]
*
* @minimumFractionDigits [Number]
*
* @maximumFractionDigits [Number]
*
* @round [Function]
*
* @roundIncrement [Function]
*
* Return the formatted integer and fraction digits.
*/
var numberFormatIntegerFractionDigits = function( number, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, round,
roundIncrement ) {
// Fraction
if ( maximumFractionDigits ) {
// Rounding
if ( roundIncrement ) {
number = round( number, roundIncrement );
// Maximum fraction digits
} else {
number = round( number, { exponent: -maximumFractionDigits } );
}
// Minimum fraction digits
if ( minimumFractionDigits ) {
number = String( number ).split( "." );
number[ 1 ] = stringPad( number[ 1 ] || "", minimumFractionDigits, true );
number = number.join( "." );
}
} else {
number = round( number );
}
number = String( number );
// Minimum integer digits
if ( minimumIntegerDigits ) {
number = number.split( "." );
number[ 0 ] = stringPad( number[ 0 ], minimumIntegerDigits );
number = number.join( "." );
}
return number;
};
/**
* toPrecision( number, precision, round )
*
* @number (Number)
*
* @precision (Number) significant figures precision (not decimal precision).
*
* @round (Function)
*
* Return number.toPrecision( precision ) using the given round function.
*/
var numberToPrecision = function( number, precision, round ) {
var roundOrder;
// Get number at two extra significant figure precision.
number = number.toPrecision( precision + 2 );
// Then, round it to the required significant figure precision.
roundOrder = Math.ceil( Math.log( Math.abs( number ) ) / Math.log( 10 ) );
roundOrder -= precision;
return round( number, { exponent: roundOrder } );
};
/**
* toPrecision( number, minimumSignificantDigits, maximumSignificantDigits, round )
*
* @number [Number]
*
* @minimumSignificantDigits [Number]
*
* @maximumSignificantDigits [Number]
*
* @round [Function]
*
* Return the formatted significant digits number.
*/
var numberFormatSignificantDigits = function( number, minimumSignificantDigits, maximumSignificantDigits, round ) {
var atMinimum, atMaximum;
// Sanity check.
if ( minimumSignificantDigits > maximumSignificantDigits ) {
maximumSignificantDigits = minimumSignificantDigits;
}
atMinimum = numberToPrecision( number, minimumSignificantDigits, round );
atMaximum = numberToPrecision( number, maximumSignificantDigits, round );
// Use atMaximum only if it has more significant digits than atMinimum.
number = +atMinimum === +atMaximum ? atMinimum : atMaximum;
// Expand integer numbers, eg. 123e5 to 12300.
number = ( +number ).toString( 10 );
if ( (/e/).test( number ) ) {
throw createErrorUnsupportedFeature({
feature: "integers out of (1e21, 1e-7)"
});
}
// Add trailing zeros if necessary.
if ( minimumSignificantDigits - number.replace( /^0+|\./g, "" ).length > 0 ) {
number = number.split( "." );
number[ 1 ] = stringPad( number[ 1 ] || "", minimumSignificantDigits - number[ 0 ].replace( /^0+/, "" ).length, true );
number = number.join( "." );
}
return number;
};
/**
* format( number, properties )
*
* @number [Number].
*
* @properties [Object] Output of number/format-properties.
*
* Return the formatted number.
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
*/
var numberFormat = function( number, properties ) {
var infinitySymbol, maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
minimumIntegerDigits, minimumSignificantDigits, nanSymbol, nuDigitsMap, padding, prefix,
primaryGroupingSize, pattern, ret, round, roundIncrement, secondaryGroupingSize, suffix,
symbolMap;
padding = properties[ 1 ];
minimumIntegerDigits = properties[ 2 ];
minimumFractionDigits = properties[ 3 ];
maximumFractionDigits = properties[ 4 ];
minimumSignificantDigits = properties[ 5 ];
maximumSignificantDigits = properties[ 6 ];
roundIncrement = properties[ 7 ];
primaryGroupingSize = properties[ 8 ];
secondaryGroupingSize = properties[ 9 ];
round = properties[ 15 ];
infinitySymbol = properties[ 16 ];
nanSymbol = properties[ 17 ];
symbolMap = properties[ 18 ];
nuDigitsMap = properties[ 19 ];
// NaN
if ( isNaN( number ) ) {
return nanSymbol;
}
if ( number < 0 ) {
pattern = properties[ 12 ];
prefix = properties[ 13 ];
suffix = properties[ 14 ];
} else {
pattern = properties[ 11 ];
prefix = properties[ 0 ];
suffix = properties[ 10 ];
}
// Infinity
if ( !isFinite( number ) ) {
return prefix + infinitySymbol + suffix;
}
ret = prefix;
// Percent
if ( pattern.indexOf( "%" ) !== -1 ) {
number *= 100;
// Per mille
} else if ( pattern.indexOf( "\u2030" ) !== -1 ) {
number *= 1000;
}
// Significant digit format
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
number = numberFormatSignificantDigits( number, minimumSignificantDigits,
maximumSignificantDigits, round );
// Integer and fractional format
} else {
number = numberFormatIntegerFractionDigits( number, minimumIntegerDigits,
minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
}
// Remove the possible number minus sign
number = number.replace( /^-/, "" );
// Grouping separators
if ( primaryGroupingSize ) {
number = numberFormatGroupingSeparator( number, primaryGroupingSize,
secondaryGroupingSize );
}
ret += number;
// Scientific notation
// TODO implement here
// Padding/'([^']|'')+'|''|[.,\-+E%\u2030]/g
// TODO implement here
ret += suffix;
return ret.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
// Literals
if ( literal ) {
literal = literal.replace( /''/, "'" );
if ( literal.length > 2 ) {
literal = literal.slice( 1, -1 );
}
return literal;
}
// Symbols
character = character.replace( /[.,\-+E%\u2030]/, function( symbol ) {
return symbolMap[ symbol ];
});
// Numbering system
if ( nuDigitsMap ) {
character = character.replace( /[0-9]/, function( digit ) {
return nuDigitsMap[ +digit ];
});
}
return character;
});
};
/**
* NumberingSystem( cldr )
*
* - http://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems
* - http://cldr.unicode.org/index/bcp47-extension
* - http://www.unicode.org/reports/tr35/#u_Extension
*/
var numberNumberingSystem = function( cldr ) {
var nu = cldr.attributes[ "u-nu" ];
if ( nu ) {
if ( nu === "traditio" ) {
nu = "traditional";
}
if ( [ "native", "traditional", "finance" ].indexOf( nu ) !== -1 ) {
// Unicode locale extension `u-nu` is set using either (native, traditional or
// finance). So, lookup the respective locale's numberingSystem and return it.
return cldr.main([ "numbers/otherNumberingSystems", nu ]);
}
// Unicode locale extension `u-nu` is set with an explicit numberingSystem. Return it.
return nu;
}
// Return the default numberingSystem.
return cldr.main( "numbers/defaultNumberingSystem" );
};
/**
* nuMap( cldr )
*
* @cldr [Cldr instance].
*
* Return digits map if numbering system is different than `latn`.
*/
var numberNumberingSystemDigitsMap = function( cldr ) {
var aux,
nu = numberNumberingSystem( cldr );
if ( nu === "latn" ) {
return;
}
aux = cldr.supplemental([ "numberingSystems", nu ]);
if ( aux._type !== "numeric" ) {
throw createErrorUnsupportedFeature( "`" + aux._type + "` numbering system" );
}
return aux._digits;
};
/**
* EBNF representation:
*
* number_pattern_re = prefix?
* padding?
* (integer_fraction_pattern | significant_pattern)
* scientific_notation?
* suffix?
*
* prefix = non_number_stuff
*
* padding = "*" regexp(.)
*
* integer_fraction_pattern = integer_pattern
* fraction_pattern?
*
* integer_pattern = regexp([#,]*[0,]*0+)
*
* fraction_pattern = "." regexp(0*[0-9]*#*)
*
* significant_pattern = regexp([#,]*@+#*)
*
* scientific_notation = regexp(E\+?0+)
*
* suffix = non_number_stuff
*
* non_number_stuff = regexp(('[^']+'|''|[^*#@0,.E])*)
*
*
* Regexp groups:
*
* 0: number_pattern_re
* 1: prefix
* 2: -
* 3: padding
* 4: (integer_fraction_pattern | significant_pattern)
* 5: integer_fraction_pattern
* 6: integer_pattern
* 7: fraction_pattern
* 8: significant_pattern
* 9: scientific_notation
* 10: suffix
* 11: -
*/
var numberPatternRe = (/^(('[^']+'|''|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/);
/**
* format( number, pattern )
*
* @number [Number].
*
* @pattern [String] raw pattern for numbers.
*
* Return the formatted number.
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
*/
var numberPatternProperties = function( pattern ) {
var aux1, aux2, fractionPattern, integerFractionOrSignificantPattern, integerPattern,
maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
minimumIntegerDigits, minimumSignificantDigits, padding, prefix, primaryGroupingSize,
roundIncrement, scientificNotation, secondaryGroupingSize, significantPattern, suffix;
pattern = pattern.match( numberPatternRe );
if ( !pattern ) {
throw new Error( "Invalid pattern: " + pattern );
}
prefix = pattern[ 1 ];
padding = pattern[ 3 ];
integerFractionOrSignificantPattern = pattern[ 4 ];
significantPattern = pattern[ 8 ];
scientificNotation = pattern[ 9 ];
suffix = pattern[ 10 ];
// Significant digit format
if ( significantPattern ) {
significantPattern.replace( /(@+)(#*)/, function( match, minimumSignificantDigitsMatch, maximumSignificantDigitsMatch ) {
minimumSignificantDigits = minimumSignificantDigitsMatch.length;
maximumSignificantDigits = minimumSignificantDigits +
maximumSignificantDigitsMatch.length;
});
// Integer and fractional format
} else {
fractionPattern = pattern[ 7 ];
integerPattern = pattern[ 6 ];
if ( fractionPattern ) {
// Minimum fraction digits, and rounding.
fractionPattern.replace( /[0-9]+/, function( match ) {
minimumFractionDigits = match;
});
if ( minimumFractionDigits ) {
roundIncrement = +( "0." + minimumFractionDigits );
minimumFractionDigits = minimumFractionDigits.length;
} else {
minimumFractionDigits = 0;
}
// Maximum fraction digits
// 1: ignore decimal character
maximumFractionDigits = fractionPattern.length - 1 /* 1 */;
}
// Minimum integer digits
integerPattern.replace( /0+$/, function( match ) {
minimumIntegerDigits = match.length;
});
}
// Scientific notation
if ( scientificNotation ) {
throw createErrorUnsupportedFeature({
feature: "scientific notation (not implemented)"
});
}
// Padding
if ( padding ) {
throw createErrorUnsupportedFeature({
feature: "padding (not implemented)"
});
}
// Grouping
if ( ( aux1 = integerFractionOrSignificantPattern.lastIndexOf( "," ) ) !== -1 ) {
// Primary grouping size is the interval between the last group separator and the end of
// the integer (or the end of the significant pattern).
aux2 = integerFractionOrSignificantPattern.split( "." )[ 0 ];
primaryGroupingSize = aux2.length - aux1 - 1;
// Secondary grouping size is the interval between the last two group separators.
if ( ( aux2 = integerFractionOrSignificantPattern.lastIndexOf( ",", aux1 - 1 ) ) !== -1 ) {
secondaryGroupingSize = aux1 - 1 - aux2;
}
}
// Return:
// 0: @prefix String
// 1: @padding Array [ <character>, <count> ] TODO
// 2: @minimumIntegerDigits non-negative integer Number value indicating the minimum integer
// digits to be used. Numbers will be padded with leading zeroes if necessary.
// 3: @minimumFractionDigits and
// 4: @maximumFractionDigits are non-negative integer Number values indicating the minimum and
// maximum fraction digits to be used. Numbers will be rounded or padded with trailing
// zeroes if necessary.
// 5: @minimumSignificantDigits and
// 6: @maximumSignificantDigits are positive integer Number values indicating the minimum and
// maximum fraction digits to be shown. Either none or both of these properties are
// present; if they are, they override minimum and maximum integer and fraction digits
// the formatter uses however many integer and fraction digits are required to display
// the specified number of significant digits.
// 7: @roundIncrement Decimal round increment or null
// 8: @primaryGroupingSize
// 9: @secondaryGroupingSize
// 10: @suffix String
return [
prefix,
padding,
minimumIntegerDigits,
minimumFractionDigits,
maximumFractionDigits,
minimumSignificantDigits,
maximumSignificantDigits,
roundIncrement,
primaryGroupingSize,
secondaryGroupingSize,
suffix
];
};
/**
* Symbol( name, cldr )
*
* @name [String] Symbol name.
*
* @cldr [Cldr instance].
*
* Return the localized symbol given its name.
*/
var numberSymbol = function( name, cldr ) {
return cldr.main([
"numbers/symbols-numberSystem-" + numberNumberingSystem( cldr ),
name
]);
};
var numberSymbolName = {
".": "decimal",
",": "group",
"%": "percentSign",
"+": "plusSign",
"-": "minusSign",
"E": "exponential",
"\u2030": "perMille"
};
/**
* symbolMap( cldr )
*
* @cldr [Cldr instance].
*
* Return the (localized symbol, pattern symbol) key value pair, eg. {
* ".": "٫",
* ",": "٬",
* "%": "٪",
* ...
* };
*/
var numberSymbolMap = function( cldr ) {
var symbol,
symbolMap = {};
for ( symbol in numberSymbolName ) {
symbolMap[ symbol ] = numberSymbol( numberSymbolName[ symbol ], cldr );
}
return symbolMap;
};
var numberTruncate = function( value ) {
if ( isNaN( value ) ) {
return NaN;
}
return Math[ value < 0 ? "ceil" : "floor" ]( value );
};
/**
* round( method )
*
* @method [String] with either "round", "ceil", "floor", or "truncate".
*
* Return function( value, incrementOrExp ):
*
* @value [Number] eg. 123.45.
*
* @incrementOrExp [Number] optional, eg. 0.1; or
* [Object] Either { increment: <value> } or { exponent: <value> }
*
* Return the rounded number, eg:
* - round( "round" )( 123.45 ): 123;
* - round( "ceil" )( 123.45 ): 124;
* - round( "floor" )( 123.45 ): 123;
* - round( "truncate" )( 123.45 ): 123;
* - round( "round" )( 123.45, 0.1 ): 123.5;
* - round( "round" )( 123.45, 10 ): 120;
*
* Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
* Ref: #376
*/
var numberRound = function( method ) {
method = method || "round";
method = method === "truncate" ? numberTruncate : Math[ method ];
return function( value, incrementOrExp ) {
var exp, increment;
value = +value;
// If the value is not a number, return NaN.
if ( isNaN( value ) ) {
return NaN;
}
// Exponent given.
if ( typeof incrementOrExp === "object" && incrementOrExp.exponent ) {
exp = +incrementOrExp.exponent;
increment = 1;
if ( exp === 0 ) {
return method( value );
}
// If the exp is not an integer, return NaN.
if ( !( typeof exp === "number" && exp % 1 === 0 ) ) {
return NaN;
}
// Increment given.
} else {
increment = +incrementOrExp || 1;
if ( increment === 1 ) {
return method( value );
}
// If the increment is not a number, return NaN.
if ( isNaN( increment ) ) {
return NaN;
}
increment = increment.toExponential().split( "e" );
exp = +increment[ 1 ];
increment = +increment[ 0 ];
}
// Shift & Round
value = value.toString().split( "e" );
value[ 0 ] = +value[ 0 ] / increment;
value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] - exp ) : -exp;
value = method( +(value[ 0 ] + "e" + value[ 1 ] ) );
// Shift back
value = value.toString().split( "e" );
value[ 0 ] = +value[ 0 ] * increment;
value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] + exp ) : exp;
return +( value[ 0 ] + "e" + value[ 1 ] );
};
};
/**
* formatProperties( pattern, cldr [, options] )
*
* @pattern [String] raw pattern for numbers.
*
* @cldr [Cldr instance].
*
* @options [Object]:
* - minimumIntegerDigits [Number]
* - minimumFractionDigits, maximumFractionDigits [Number]
* - minimumSignificantDigits, maximumSignificantDigits [Number]
* - round [String] "ceil", "floor", "round" (default), or "truncate".
* - useGrouping [Boolean] default true.
*
* Return the processed properties that will be used in number/format.
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
*/
var numberFormatProperties = function( pattern, cldr, options ) {
var negativePattern, negativePrefix, negativeProperties, negativeSuffix, positivePattern,
properties;
function getOptions( attribute, propertyIndex ) {
if ( attribute in options ) {
properties[ propertyIndex ] = options[ attribute ];
}
}
options = options || {};
pattern = pattern.split( ";" );
positivePattern = pattern[ 0 ];
negativePattern = pattern[ 1 ] || "-" + positivePattern;
negativeProperties = numberPatternProperties( negativePattern );
negativePrefix = negativeProperties[ 0 ];
negativeSuffix = negativeProperties[ 10 ];
properties = numberPatternProperties( positivePattern ).concat([
positivePattern,
negativePrefix + positivePattern + negativeSuffix,
negativePrefix,
negativeSuffix,
numberRound( options.round ),
numberSymbol( "infinity", cldr ),
numberSymbol( "nan", cldr ),
numberSymbolMap( cldr ),
numberNumberingSystemDigitsMap( cldr )
]);
getOptions( "minimumIntegerDigits", 2 );
getOptions( "minimumFractionDigits", 3 );
getOptions( "maximumFractionDigits", 4 );
getOptions( "minimumSignificantDigits", 5 );
getOptions( "maximumSignificantDigits", 6 );
// Grouping separators
if ( options.useGrouping === false ) {
properties[ 8 ] = null;
}
// Normalize number of digits if only one of either minimumFractionDigits or
// maximumFractionDigits is passed in as an option
if ( "minimumFractionDigits" in options && !( "maximumFractionDigits" in options ) ) {
// maximumFractionDigits = Math.max( minimumFractionDigits, maximumFractionDigits );
properties[ 4 ] = Math.max( properties[ 3 ], properties[ 4 ] );
} else if ( !( "minimumFractionDigits" in options ) &&
"maximumFractionDigits" in options ) {
// minimumFractionDigits = Math.min( minimumFractionDigits, maximumFractionDigits );
properties[ 3 ] = Math.min( properties[ 3 ], properties[ 4 ] );
}
// Return:
// 0-10: see number/pattern-properties.
// 11: @positivePattern [String] Positive pattern.
// 12: @negativePattern [String] Negative pattern.
// 13: @negativePrefix [String] Negative prefix.
// 14: @negativeSuffix [String] Negative suffix.
// 15: @round [Function] Round function.
// 16: @infinitySymbol [String] Infinity symbol.
// 17: @nanSymbol [String] NaN symbol.
// 18: @symbolMap [Object] A bunch of other symbols.
// 19: @nuDigitsMap [Array] Digits map if numbering system is different than `latn`.
return properties;
};
/**
* EBNF representation:
*
* number_pattern_re = prefix_including_padding?
* number
* scientific_notation?
* suffix?
*
* number = integer_including_group_separator fraction_including_decimal_separator
*
* integer_including_group_separator =
* regexp([0-9,]*[0-9]+)
*
* fraction_including_decimal_separator =
* regexp((\.[0-9]+)?)
* prefix_including_padding = non_number_stuff
*
* scientific_notation = regexp(E[+-]?[0-9]+)
*
* suffix = non_number_stuff
*
* non_number_stuff = regexp([^0-9]*)
*
*
* Regexp groups:
*
* 0: number_pattern_re
* 1: prefix
* 2: integer_including_group_separator fraction_including_decimal_separator
* 3: integer_including_group_separator
* 4: fraction_including_decimal_separator
* 5: scientific_notation
* 6: suffix
*/
var numberNumberRe = (/^([^0-9]*)(([0-9,]*[0-9]+)(\.[0-9]+)?)(E[+-]?[0-9]+)?([^0-9]*)$/);
/**
* parse( value, properties )
*
* @value [String].
*
* @properties [Object] Parser properties is a reduced pre-processed cldr
* data set returned by numberParserProperties().
*
* Return the parsed Number (including Infinity) or NaN when value is invalid.
* ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
*/
var numberParse = function( value, properties ) {
var aux, infinitySymbol, invertedNuDigitsMap, invertedSymbolMap, localizedDigitRe,
localizedSymbolsRe, negativePrefix, negativeSuffix, number, prefix, suffix;
infinitySymbol = properties[ 0 ];
invertedSymbolMap = properties[ 1 ];
negativePrefix = properties[ 2 ];
negativeSuffix = properties[ 3 ];
invertedNuDigitsMap = properties[ 4 ];
// Infinite number.
if ( aux = value.match( infinitySymbol ) ) {
number = Infinity;
prefix = value.slice( 0, aux.length );
suffix = value.slice( aux.length + 1 );
// Finite number.
} else {
// TODO: Create it during setup, i.e., make it a property.
localizedSymbolsRe = new RegExp(
Object.keys( invertedSymbolMap ).map(function( localizedSymbol ) {
return regexpEscape( localizedSymbol );
}).join( "|" ),
"g"
);
// Reverse localized symbols.
value = value.replace( localizedSymbolsRe, function( localizedSymbol ) {
return invertedSymbolMap[ localizedSymbol ];
});
// Reverse localized numbering system.
if ( invertedNuDigitsMap ) {
// TODO: Create it during setup, i.e., make it a property.
localizedDigitRe = new RegExp(
Object.keys( invertedNuDigitsMap ).map(function( localizedDigit ) {
return regexpEscape( localizedDigit );
}).join( "|" ),
"g"
);
value = value.replace( localizedDigitRe, function( localizedDigit ) {
return invertedNuDigitsMap[ localizedDigit ];
});
}
// Is it a valid number?
value = value.match( numberNumberRe );
if ( !value ) {
// Invalid number.
return NaN;
}
prefix = value[ 1 ];
suffix = value[ 6 ];
// Remove grouping separators.
number = value[ 2 ].replace( /,/g, "" );
// Scientific notation
if ( value[ 5 ] ) {
number += value[ 5 ];
}
number = +number;
// Is it a valid number?
if ( isNaN( number ) ) {
// Invalid number.
return NaN;
}
// Percent
if ( value[ 0 ].indexOf( "%" ) !== -1 ) {
number /= 100;
suffix = suffix.replace( "%", "" );
// Per mille
} else if ( value[ 0 ].indexOf( "\u2030" ) !== -1 ) {
number /= 1000;
suffix = suffix.replace( "\u2030", "" );
}
}
// Negative number
// "If there is an explicit negative subpattern, it serves only to specify the negative prefix
// and suffix. If there is no explicit negative subpattern, the negative subpattern is the
// localized minus sign prefixed to the positive subpattern" UTS#35
if ( prefix === negativePrefix && suffix === negativeSuffix ) {
number *= -1;
}
return number;
};
/**
* symbolMap( cldr )
*
* @cldr [Cldr instance].
*
* Return the (localized symbol, pattern symbol) key value pair, eg. {
* "٫": ".",
* "٬": ",",
* "٪": "%",
* ...
* };
*/
var numberSymbolInvertedMap = function( cldr ) {
var symbol,
symbolMap = {};
for ( symbol in numberSymbolName ) {
symbolMap[ numberSymbol( numberSymbolName[ symbol ], cldr ) ] = symbol;
}
return symbolMap;
};
/**
* parseProperties( pattern, cldr )
*
* @pattern [String] raw pattern for numbers.
*
* @cldr [Cldr instance].
*
* Return parser properties, used to feed parser function.
*/
var numberParseProperties = function( pattern, cldr ) {
var invertedNuDigitsMap, invertedNuDigitsMapSanityCheck, negativePattern, negativeProperties,
nuDigitsMap = numberNumberingSystemDigitsMap( cldr );
pattern = pattern.split( ";" );
negativePattern = pattern[ 1 ] || "-" + pattern[ 0 ];
negativeProperties = numberPatternProperties( negativePattern );
if ( nuDigitsMap ) {
invertedNuDigitsMap = nuDigitsMap.split( "" ).reduce(function( object, localizedDigit, i ) {
object[ localizedDigit ] = String( i );
return object;
}, {} );
invertedNuDigitsMapSanityCheck = "0123456789".split( "" ).reduce(function( object, digit ) {
object[ digit ] = "invalid";
return object;
}, {} );
invertedNuDigitsMap = objectExtend(
invertedNuDigitsMapSanityCheck,
invertedNuDigitsMap
);
}
// 0: @infinitySymbol [String] Infinity symbol.
// 1: @invertedSymbolMap [Object] Inverted symbol map augmented with sanity check.
// The sanity check prevents permissive parsing, i.e., it prevents symbols that doesn't
// belong to the localized set to pass through. This is obtained with the result of the
// inverted map object overloading symbol name map object (the remaining symbol name
// mappings will invalidate parsing, working as the sanity check).
// 2: @negativePrefix [String] Negative prefix.
// 3: @negativeSuffix [String] Negative suffix with percent or per mille stripped out.
// 4: @invertedNuDigitsMap [Object] Inverted digits map if numbering system is different than
// `latn` augmented with sanity check (similar to invertedSymbolMap).
return [
numberSymbol( "infinity", cldr ),
objectExtend( {}, numberSymbolName, numberSymbolInvertedMap( cldr ) ),
negativeProperties[ 0 ],
negativeProperties[ 10 ].replace( "%", "" ).replace( "\u2030", "" ),
invertedNuDigitsMap
];
};
/**
* Pattern( style )
*
* @style [String] "decimal" (default) or "percent".
*
* @cldr [Cldr instance].
*/
var numberPattern = function( style, cldr ) {
if ( style !== "decimal" && style !== "percent" ) {
throw new Error( "Invalid style" );
}
return cldr.main([
"numbers",
style + "Formats-numberSystem-" + numberNumberingSystem( cldr ),
"standard"
]);
};
/**
* .numberFormatter( [options] )
*
* @options [Object]:
* - style: [String] "decimal" (default) or "percent".
* - see also number/format options.
*
* Return a function that formats a number according to the given options and default/instance
* locale.
*/
Globalize.numberFormatter =
Globalize.prototype.numberFormatter = function( options ) {
var cldr, maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
minimumIntegerDigits, minimumSignificantDigits, pattern, properties;
validateParameterTypePlainObject( options, "options" );
options = options || {};
cldr = this.cldr;
validateDefaultLocale( cldr );
cldr.on( "get", validateCldr );
if ( options.raw ) {
pattern = options.raw;
} else {
pattern = numberPattern( options.style || "decimal", cldr );
}
properties = numberFormatProperties( pattern, cldr, options );
cldr.off( "get", validateCldr );
minimumIntegerDigits = properties[ 2 ];
minimumFractionDigits = properties[ 3 ];
maximumFractionDigits = properties[ 4 ];
minimumSignificantDigits = properties[ 5 ];
maximumSignificantDigits = properties[ 6 ];
// Validate significant digit format properties
if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
validateParameterRange( minimumSignificantDigits, "minimumSignificantDigits", 1, 21 );
validateParameterRange( maximumSignificantDigits, "maximumSignificantDigits",
minimumSignificantDigits, 21 );
} else if ( !isNaN( minimumSignificantDigits ) || !isNaN( maximumSignificantDigits ) ) {
throw new Error( "Neither or both the minimum and maximum significant digits must be " +
"present" );
// Validate integer and fractional format
} else {
validateParameterRange( minimumIntegerDigits, "minimumIntegerDigits", 1, 21 );
validateParameterRange( minimumFractionDigits, "minimumFractionDigits", 0, 20 );
validateParameterRange( maximumFractionDigits, "maximumFractionDigits",
minimumFractionDigits, 20 );
}
return function( value ) {
validateParameterPresence( value, "value" );
validateParameterTypeNumber( value, "value" );
return numberFormat( value, properties );
};
};
/**
* .numberParser( [options] )
*
* @options [Object]:
* - style: [String] "decimal" (default) or "percent".
*
* Return the number parser according to the default/instance locale.
*/
Globalize.numberParser =
Globalize.prototype.numberParser = function( options ) {
var cldr, pattern, properties;
validateParameterTypePlainObject( options, "options" );
options = options || {};
cldr = this.cldr;
validateDefaultLocale( cldr );
cldr.on( "get", validateCldr );
if ( options.raw ) {
pattern = options.raw;
} else {
pattern = numberPattern( options.style || "decimal", cldr );
}
properties = numberParseProperties( pattern, cldr );
cldr.off( "get", validateCldr );
return function( value ) {
validateParameterPresence( value, "value" );
validateParameterTypeString( value, "value" );
return numberParse( value, properties );
};
};
/**
* .formatNumber( value [, options] )
*
* @value [Number] number to be formatted.
*
* @options [Object]: see number/format-properties.
*
* Format a number according to the given options and default/instance locale.
*/
Globalize.formatNumber =
Globalize.prototype.formatNumber = function( value, options ) {
validateParameterPresence( value, "value" );
validateParameterTypeNumber( value, "value" );
return this.numberFormatter( options )( value );
};
/**
* .parseNumber( value [, options] )
*
* @value [String]
*
* @options [Object]: See numberParser().
*
* Return the parsed Number (including Infinity) or NaN when value is invalid.
*/
Globalize.parseNumber =
Globalize.prototype.parseNumber = function( value, options ) {
validateParameterPresence( value, "value" );
validateParameterTypeString( value, "value" );
return this.numberParser( options )( value );
};
/**
* Optimization to avoid duplicating some internal functions across modules.
*/
Globalize._createErrorUnsupportedFeature = createErrorUnsupportedFeature;
Globalize._numberNumberingSystem = numberNumberingSystem;
Globalize._numberPattern = numberPattern;
Globalize._numberSymbol = numberSymbol;
Globalize._stringPad = stringPad;
Globalize._validateParameterTypeNumber = validateParameterTypeNumber;
Globalize._validateParameterTypeString = validateParameterTypeString;
return Globalize;
}));