aboutsummaryrefslogtreecommitdiffstats
path: root/external/globalize/globalize-runtime/number.js
diff options
context:
space:
mode:
Diffstat (limited to 'external/globalize/globalize-runtime/number.js')
-rw-r--r--external/globalize/globalize-runtime/number.js682
1 files changed, 682 insertions, 0 deletions
diff --git a/external/globalize/globalize-runtime/number.js b/external/globalize/globalize-runtime/number.js
new file mode 100644
index 000000000..b3031471a
--- /dev/null
+++ b/external/globalize/globalize-runtime/number.js
@@ -0,0 +1,682 @@
+/**
+ * Globalize Runtime v1.1.0-rc.6
+ *
+ * http://github.com/jquery/globalize
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-11-18T10:38Z
+ */
+/*!
+ * Globalize Runtime v1.1.0-rc.6 2015-11-18T10:38Z Released under the MIT license
+ * http://git.io/TrdQbw
+ */
+(function( root, factory ) {
+
+ // UMD returnExports
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD
+ define([
+ "../globalize-runtime"
+ ], factory );
+ } else if ( typeof exports === "object" ) {
+
+ // Node, CommonJS
+ module.exports = factory( require( "../globalize-runtime" ) );
+ } else {
+
+ // Extend global
+ factory( root.Globalize );
+ }
+}(this, function( Globalize ) {
+
+var createError = Globalize._createError,
+ regexpEscape = Globalize._regexpEscape,
+ runtimeKey = Globalize._runtimeKey,
+ stringPad = Globalize._stringPad,
+ validateParameterType = Globalize._validateParameterType,
+ validateParameterPresence = Globalize._validateParameterPresence,
+ validateParameterTypeString = Globalize._validateParameterTypeString;
+
+
+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"
+ );
+};
+
+
+
+
+/**
+ * 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;
+ });
+};
+
+
+
+
+var numberFormatterFn = function( properties ) {
+ return function numberFormatter( value ) {
+ validateParameterPresence( value, "value" );
+ validateParameterTypeNumber( value, "value" );
+
+ return numberFormat( value, 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 ];
+ });
+ }
+
+ // Add padding zero to leading decimal.
+ if ( value.charAt( 0 ) === "." ) {
+ value = "0" + value;
+ }
+
+ // 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;
+};
+
+
+
+
+var numberParserFn = function( properties ) {
+ return function numberParser( value ) {
+ validateParameterPresence( value, "value" );
+ validateParameterTypeString( value, "value" );
+
+ return numberParse( value, properties );
+ };
+
+};
+
+
+
+
+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 ] );
+ };
+};
+
+
+
+
+Globalize._createErrorUnsupportedFeature = createErrorUnsupportedFeature;
+Globalize._numberFormat = numberFormat;
+Globalize._numberFormatterFn = numberFormatterFn;
+Globalize._numberParse = numberParse;
+Globalize._numberParserFn = numberParserFn;
+Globalize._numberRound = numberRound;
+Globalize._validateParameterPresence = validateParameterPresence;
+Globalize._validateParameterTypeNumber = validateParameterTypeNumber;
+Globalize._validateParameterTypeString = validateParameterTypeString;
+
+Globalize.numberFormatter =
+Globalize.prototype.numberFormatter = function( options ) {
+ options = options || {};
+ return Globalize[ runtimeKey( "numberFormatter", this._locale, [ options ] ) ];
+};
+
+Globalize.numberParser =
+Globalize.prototype.numberParser = function( options ) {
+ options = options || {};
+ return Globalize[ runtimeKey( "numberParser", this._locale, [ options ] ) ];
+};
+
+Globalize.formatNumber =
+Globalize.prototype.formatNumber = function( value, options ) {
+ validateParameterPresence( value, "value" );
+ validateParameterTypeNumber( value, "value" );
+
+ return this.numberFormatter( options )( value );
+};
+
+Globalize.parseNumber =
+Globalize.prototype.parseNumber = function( value, options ) {
+ validateParameterPresence( value, "value" );
+ validateParameterTypeString( value, "value" );
+
+ return this.numberParser( options )( value );
+};
+
+return Globalize;
+
+
+
+
+}));