mirror of
				https://github.com/1disk/edp445.git
				synced 2024-08-14 22:47:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1737 lines
		
	
	
	
		
			60 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1737 lines
		
	
	
	
		
			60 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*! Moment Duration Format v2.2.2
 | |
|  *  https://github.com/jsmreese/moment-duration-format
 | |
|  *  Date: 2018-02-16
 | |
|  *
 | |
|  *  Duration format plugin function for the Moment.js library
 | |
|  *  http://momentjs.com/
 | |
|  *
 | |
|  *  Copyright 2018 John Madhavan-Reese
 | |
|  *  Released under the MIT license
 | |
|  */
 | |
| 
 | |
| (function (root, factory) {
 | |
|     if (typeof define === 'function' && define.amd) {
 | |
|         // AMD. Register as an anonymous module.
 | |
|         define(['moment'], factory);
 | |
|     } else if (typeof exports === 'object') {
 | |
|         // Node. Does not work with strict CommonJS, but only CommonJS-like
 | |
|         // enviroments that support module.exports, like Node.
 | |
|         try {
 | |
|             module.exports = factory(require('moment'));
 | |
|         } catch (e) {
 | |
|             // If moment is not available, leave the setup up to the user.
 | |
|             // Like when using moment-timezone or similar moment-based package.
 | |
|             module.exports = factory;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (root) {
 | |
|         // Globals.
 | |
|         root.momentDurationFormatSetup = root.moment ? factory(root.moment) : factory;
 | |
|     }
 | |
| })(this, function (moment) {
 | |
|     // `Number#tolocaleString` is tested on plugin initialization.
 | |
|     // If the feature test passes, `toLocaleStringWorks` will be set to `true` and the
 | |
|     // native function will be used to generate formatted output. If the feature
 | |
|     // test fails, the fallback format function internal to this plugin will be
 | |
|     // used.
 | |
|     var toLocaleStringWorks = false;
 | |
| 
 | |
|     // `Number#toLocaleString` rounds incorrectly for select numbers in Microsoft
 | |
|     // environments (Edge, IE11, Windows Phone) and possibly other environments.
 | |
|     // If the rounding test fails and `toLocaleString` will be used for formatting,
 | |
|     // the plugin will "pre-round" number values using the fallback number format
 | |
|     // function before passing them to `toLocaleString` for final formatting.
 | |
|     var toLocaleStringRoundingWorks = false;
 | |
| 
 | |
|     // `Intl.NumberFormat#format` is tested on plugin initialization.
 | |
|     // If the feature test passes, `intlNumberFormatRoundingWorks` will be set to
 | |
|     // `true` and the native function will be used to generate formatted output.
 | |
|     // If the feature test fails, either `Number#tolocaleString` (if
 | |
|     // `toLocaleStringWorks` is `true`), or the fallback format function internal
 | |
|     //  to this plugin will be used.
 | |
|     var intlNumberFormatWorks = false;
 | |
| 
 | |
|     // `Intl.NumberFormat#format` rounds incorrectly for select numbers in Microsoft
 | |
|     // environments (Edge, IE11, Windows Phone) and possibly other environments.
 | |
|     // If the rounding test fails and `Intl.NumberFormat#format` will be used for
 | |
|     // formatting, the plugin will "pre-round" number values using the fallback number
 | |
|     // format function before passing them to `Intl.NumberFormat#format` for final
 | |
|     // formatting.
 | |
|     var intlNumberFormatRoundingWorks = false;
 | |
| 
 | |
|     // Token type names in order of descending magnitude.
 | |
|     var types = "escape years months weeks days hours minutes seconds milliseconds general".split(" ");
 | |
| 
 | |
|     var bubbles = [
 | |
|         {
 | |
|             type: "seconds",
 | |
|             targets: [
 | |
|                 { type: "minutes", value: 60 },
 | |
|                 { type: "hours", value: 3600 },
 | |
|                 { type: "days", value: 86400 },
 | |
|                 { type: "weeks", value: 604800 },
 | |
|                 { type: "months", value: 2678400 },
 | |
|                 { type: "years", value: 31536000 }
 | |
|             ]
 | |
|         },
 | |
|         {
 | |
|             type: "minutes",
 | |
|             targets: [
 | |
|                 { type: "hours", value: 60 },
 | |
|                 { type: "days", value: 1440 },
 | |
|                 { type: "weeks", value: 10080 },
 | |
|                 { type: "months", value: 44640 },
 | |
|                 { type: "years", value: 525600 }
 | |
|             ]
 | |
|         },
 | |
|         {
 | |
|             type: "hours",
 | |
|             targets: [
 | |
|                 { type: "days", value: 24 },
 | |
|                 { type: "weeks", value: 168 },
 | |
|                 { type: "months", value: 744 },
 | |
|                 { type: "years", value: 8760 }
 | |
|             ]
 | |
|         },
 | |
|         {
 | |
|             type: "days",
 | |
|             targets: [
 | |
|                 { type: "weeks", value: 7 },
 | |
|                 { type: "months", value: 31 },
 | |
|                 { type: "years", value: 365 }
 | |
|             ]
 | |
|         },
 | |
|         {
 | |
|             type: "months",
 | |
|             targets: [
 | |
|                 { type: "years", value: 12 }
 | |
|             ]
 | |
|         }
 | |
|     ];
 | |
| 
 | |
|     // stringIncludes
 | |
|     function stringIncludes(str, search) {
 | |
|         if (search.length > str.length) {
 | |
|           return false;
 | |
|         }
 | |
| 
 | |
|         return str.indexOf(search) !== -1;
 | |
|     }
 | |
| 
 | |
|     // repeatZero(qty)
 | |
|     // Returns "0" repeated `qty` times.
 | |
|     // `qty` must be a integer >= 0.
 | |
|     function repeatZero(qty) {
 | |
|         var result = "";
 | |
| 
 | |
|         while (qty) {
 | |
|             result += "0";
 | |
|             qty -= 1;
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     function stringRound(digits) {
 | |
|         var digitsArray = digits.split("").reverse();
 | |
|         var i = 0;
 | |
|         var carry = true;
 | |
| 
 | |
|         while (carry && i < digitsArray.length) {
 | |
|             if (i) {
 | |
|                 if (digitsArray[i] === "9") {
 | |
|                     digitsArray[i] = "0";
 | |
|                 } else {
 | |
|                     digitsArray[i] = (parseInt(digitsArray[i], 10) + 1).toString();
 | |
|                     carry = false;
 | |
|                 }
 | |
|             } else {
 | |
|                 if (parseInt(digitsArray[i], 10) < 5) {
 | |
|                     carry = false;
 | |
|                 }
 | |
| 
 | |
|                 digitsArray[i] = "0";
 | |
|             }
 | |
| 
 | |
|             i += 1;
 | |
|         }
 | |
| 
 | |
|         if (carry) {
 | |
|             digitsArray.push("1");
 | |
|         }
 | |
| 
 | |
|         return digitsArray.reverse().join("");
 | |
|     }
 | |
| 
 | |
|     // cachedNumberFormat
 | |
|     // Returns an `Intl.NumberFormat` instance for the given locale and configuration.
 | |
|     // On first use of a particular configuration, the instance is cached for fast
 | |
|     // repeat access.
 | |
|     function cachedNumberFormat(locale, options) {
 | |
|         // Create a sorted, stringified version of `options`
 | |
|         // for use as part of the cache key
 | |
|         var optionsString = map(
 | |
|             keys(options).sort(),
 | |
|             function(key) {
 | |
|                 return key + ':' + options[key];
 | |
|             }
 | |
|         ).join(',');
 | |
| 
 | |
|         // Set our cache key
 | |
|         var cacheKey = locale + '+' + optionsString;
 | |
| 
 | |
|         // If we don't have this configuration cached, configure and cache it
 | |
|         if (!cachedNumberFormat.cache[cacheKey]) {
 | |
|             cachedNumberFormat.cache[cacheKey] = Intl.NumberFormat(locale, options);
 | |
|         }
 | |
| 
 | |
|         // Return the cached version of this configuration
 | |
|         return cachedNumberFormat.cache[cacheKey];
 | |
|     }
 | |
|     cachedNumberFormat.cache = {};
 | |
| 
 | |
|     // formatNumber
 | |
|     // Formats any number greater than or equal to zero using these options:
 | |
|     // - userLocale
 | |
|     // - useToLocaleString
 | |
|     // - useGrouping
 | |
|     // - grouping
 | |
|     // - maximumSignificantDigits
 | |
|     // - minimumIntegerDigits
 | |
|     // - fractionDigits
 | |
|     // - groupingSeparator
 | |
|     // - decimalSeparator
 | |
|     //
 | |
|     // `useToLocaleString` will use `Intl.NumberFormat` or `toLocaleString` for formatting.
 | |
|     // `userLocale` option is passed through to the formatting function.
 | |
|     // `fractionDigits` is passed through to `maximumFractionDigits` and `minimumFractionDigits`
 | |
|     // Using `maximumSignificantDigits` will override `minimumIntegerDigits` and `fractionDigits`.
 | |
|     function formatNumber(number, options, userLocale) {
 | |
|         var useToLocaleString = options.useToLocaleString;
 | |
|         var useGrouping = options.useGrouping;
 | |
|         var grouping = useGrouping && options.grouping.slice();
 | |
|         var maximumSignificantDigits = options.maximumSignificantDigits;
 | |
|         var minimumIntegerDigits = options.minimumIntegerDigits || 1;
 | |
|         var fractionDigits = options.fractionDigits || 0;
 | |
|         var groupingSeparator = options.groupingSeparator;
 | |
|         var decimalSeparator = options.decimalSeparator;
 | |
| 
 | |
|         if (useToLocaleString && userLocale) {
 | |
|             var localeStringOptions = {
 | |
|                 minimumIntegerDigits: minimumIntegerDigits,
 | |
|                 useGrouping: useGrouping
 | |
|             };
 | |
| 
 | |
|             if (fractionDigits) {
 | |
|                 localeStringOptions.maximumFractionDigits = fractionDigits;
 | |
|                 localeStringOptions.minimumFractionDigits = fractionDigits;
 | |
|             }
 | |
| 
 | |
|             // toLocaleString output is "0.0" instead of "0" for HTC browsers
 | |
|             // when maximumSignificantDigits is set. See #96.
 | |
|             if (maximumSignificantDigits && number > 0) {
 | |
|                 localeStringOptions.maximumSignificantDigits = maximumSignificantDigits;
 | |
|             }
 | |
| 
 | |
|             if (intlNumberFormatWorks) {
 | |
|                 if (!intlNumberFormatRoundingWorks) {
 | |
|                     var roundingOptions = extend({}, options);
 | |
|                     roundingOptions.useGrouping = false;
 | |
|                     roundingOptions.decimalSeparator = ".";
 | |
|                     number = parseFloat(formatNumber(number, roundingOptions), 10);
 | |
|                 }
 | |
| 
 | |
|                 return cachedNumberFormat(userLocale, localeStringOptions).format(number);
 | |
|             } else {
 | |
|                 if (!toLocaleStringRoundingWorks) {
 | |
|                     var roundingOptions = extend({}, options);
 | |
|                     roundingOptions.useGrouping = false;
 | |
|                     roundingOptions.decimalSeparator = ".";
 | |
|                     number = parseFloat(formatNumber(number, roundingOptions), 10);
 | |
|                 }
 | |
| 
 | |
|                 return number.toLocaleString(userLocale, localeStringOptions);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         var numberString;
 | |
| 
 | |
|         // Add 1 to digit output length for floating point errors workaround. See below.
 | |
|         if (maximumSignificantDigits) {
 | |
|             numberString = number.toPrecision(maximumSignificantDigits + 1);
 | |
|         } else {
 | |
|             numberString = number.toFixed(fractionDigits + 1);
 | |
|         }
 | |
| 
 | |
|         var integerString;
 | |
|         var fractionString;
 | |
|         var exponentString;
 | |
| 
 | |
|         var temp = numberString.split("e");
 | |
| 
 | |
|         exponentString = temp[1] || "";
 | |
| 
 | |
|         temp = temp[0].split(".");
 | |
| 
 | |
|         fractionString = temp[1] || "";
 | |
|         integerString = temp[0] || "";
 | |
| 
 | |
|         // Workaround for floating point errors in `toFixed` and `toPrecision`.
 | |
|         // (3.55).toFixed(1); --> "3.5"
 | |
|         // (123.55 - 120).toPrecision(2); --> "3.5"
 | |
|         // (123.55 - 120); --> 3.549999999999997
 | |
|         // (123.55 - 120).toFixed(2); --> "3.55"
 | |
|         // Round by examing the string output of the next digit.
 | |
| 
 | |
|         // *************** Implement String Rounding here ***********************
 | |
|         // Check integerString + fractionString length of toPrecision before rounding.
 | |
|         // Check length of fractionString from toFixed output before rounding.
 | |
|         var integerLength = integerString.length;
 | |
|         var fractionLength = fractionString.length;
 | |
|         var digitCount = integerLength + fractionLength;
 | |
|         var digits = integerString + fractionString;
 | |
| 
 | |
|         if (maximumSignificantDigits && digitCount === (maximumSignificantDigits + 1) || !maximumSignificantDigits && fractionLength === (fractionDigits + 1)) {
 | |
|             // Round digits.
 | |
|             digits = stringRound(digits);
 | |
| 
 | |
|             if (digits.length === digitCount + 1) {
 | |
|                 integerLength = integerLength + 1;
 | |
|             }
 | |
| 
 | |
|             // Discard final fractionDigit.
 | |
|             if (fractionLength) {
 | |
|                 digits = digits.slice(0, -1);
 | |
|             }
 | |
| 
 | |
|             // Separate integer and fraction.
 | |
|             integerString = digits.slice(0, integerLength);
 | |
|             fractionString = digits.slice(integerLength);
 | |
|         }
 | |
| 
 | |
|         // Trim trailing zeroes from fractionString because toPrecision outputs
 | |
|         // precision, not significant digits.
 | |
|         if (maximumSignificantDigits) {
 | |
|             fractionString = fractionString.replace(/0*$/, "");
 | |
|         }
 | |
| 
 | |
|         // Handle exponent.
 | |
|         var exponent = parseInt(exponentString, 10);
 | |
| 
 | |
|         if (exponent > 0) {
 | |
|             if (fractionString.length <= exponent) {
 | |
|                 fractionString = fractionString + repeatZero(exponent - fractionString.length);
 | |
| 
 | |
|                 integerString = integerString + fractionString;
 | |
|                 fractionString = "";
 | |
|             } else {
 | |
|                 integerString = integerString + fractionString.slice(0, exponent);
 | |
|                 fractionString = fractionString.slice(exponent);
 | |
|             }
 | |
|         } else if (exponent < 0) {
 | |
|             fractionString = (repeatZero(Math.abs(exponent) - integerString.length) + integerString + fractionString);
 | |
| 
 | |
|             integerString = "0";
 | |
|         }
 | |
| 
 | |
|         if (!maximumSignificantDigits) {
 | |
|             // Trim or pad fraction when not using maximumSignificantDigits.
 | |
|             fractionString = fractionString.slice(0, fractionDigits);
 | |
| 
 | |
|             if (fractionString.length < fractionDigits) {
 | |
|                 fractionString = fractionString + repeatZero(fractionDigits - fractionString.length);
 | |
|             }
 | |
| 
 | |
|             // Pad integer when using minimumIntegerDigits
 | |
|             // and not using maximumSignificantDigits.
 | |
|             if (integerString.length < minimumIntegerDigits) {
 | |
|                 integerString = repeatZero(minimumIntegerDigits - integerString.length) + integerString;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         var formattedString = "";
 | |
| 
 | |
|         // Handle grouping.
 | |
|         if (useGrouping) {
 | |
|             temp = integerString;
 | |
|             var group;
 | |
| 
 | |
|             while (temp.length) {
 | |
|                 if (grouping.length) {
 | |
|                     group = grouping.shift();
 | |
|                 }
 | |
| 
 | |
|                 if (formattedString) {
 | |
|                     formattedString = groupingSeparator + formattedString;
 | |
|                 }
 | |
| 
 | |
|                 formattedString = temp.slice(-group) + formattedString;
 | |
| 
 | |
|                 temp = temp.slice(0, -group);
 | |
|             }
 | |
|         } else {
 | |
|             formattedString = integerString;
 | |
|         }
 | |
| 
 | |
|         // Add decimalSeparator and fraction.
 | |
|         if (fractionString) {
 | |
|             formattedString = formattedString + decimalSeparator + fractionString;
 | |
|         }
 | |
| 
 | |
|         return formattedString;
 | |
|     }
 | |
| 
 | |
|     // durationLabelCompare
 | |
|     function durationLabelCompare(a, b) {
 | |
|         if (a.label.length > b.label.length) {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         if (a.label.length < b.label.length) {
 | |
|             return 1;
 | |
|         }
 | |
| 
 | |
|         // a must be equal to b
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     // durationGetLabels
 | |
|     function durationGetLabels(token, localeData) {
 | |
|         var labels = [];
 | |
| 
 | |
|         each(keys(localeData), function (localeDataKey) {
 | |
|             if (localeDataKey.slice(0, 15) !== "_durationLabels") {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             var labelType = localeDataKey.slice(15).toLowerCase();
 | |
| 
 | |
|             each(keys(localeData[localeDataKey]), function (labelKey) {
 | |
|                 if (labelKey.slice(0, 1) === token) {
 | |
|                     labels.push({
 | |
|                         type: labelType,
 | |
|                         key: labelKey,
 | |
|                         label: localeData[localeDataKey][labelKey]
 | |
|                     });
 | |
|                 }
 | |
|             });
 | |
|         });
 | |
| 
 | |
|         return labels;
 | |
|     }
 | |
| 
 | |
|     // durationPluralKey
 | |
|     function durationPluralKey(token, integerValue, decimalValue) {
 | |
|         // Singular for a value of `1`, but not for `1.0`.
 | |
|         if (integerValue === 1 && decimalValue === null) {
 | |
|             return token;
 | |
|         }
 | |
| 
 | |
|         return token + token;
 | |
|     }
 | |
| 
 | |
|     var engLocale = {
 | |
|         durationLabelsStandard: {
 | |
|             S: 'millisecond',
 | |
|             SS: 'milliseconds',
 | |
|             s: 'second',
 | |
|             ss: 'seconds',
 | |
|             m: 'minute',
 | |
|             mm: 'minutes',
 | |
|             h: 'hour',
 | |
|             hh: 'hours',
 | |
|             d: 'day',
 | |
|             dd: 'days',
 | |
|             w: 'week',
 | |
|             ww: 'weeks',
 | |
|             M: 'month',
 | |
|             MM: 'months',
 | |
|             y: 'year',
 | |
|             yy: 'years'
 | |
|         },
 | |
|         durationLabelsShort: {
 | |
|             S: 'msec',
 | |
|             SS: 'msecs',
 | |
|             s: 'sec',
 | |
|             ss: 'secs',
 | |
|             m: 'min',
 | |
|             mm: 'mins',
 | |
|             h: 'hr',
 | |
|             hh: 'hrs',
 | |
|             d: 'dy',
 | |
|             dd: 'dys',
 | |
|             w: 'wk',
 | |
|             ww: 'wks',
 | |
|             M: 'mo',
 | |
|             MM: 'mos',
 | |
|             y: 'yr',
 | |
|             yy: 'yrs'
 | |
|         },
 | |
|         durationTimeTemplates: {
 | |
|             HMS: 'h:mm:ss',
 | |
|             HM: 'h:mm',
 | |
|             MS: 'm:ss'
 | |
|         },
 | |
|         durationLabelTypes: [
 | |
|             { type: "standard", string: "__" },
 | |
|             { type: "short", string: "_" }
 | |
|         ],
 | |
|         durationPluralKey: durationPluralKey
 | |
|     };
 | |
| 
 | |
|     // isArray
 | |
|     function isArray(array) {
 | |
|         return Object.prototype.toString.call(array) === "[object Array]";
 | |
|     }
 | |
| 
 | |
|     // isObject
 | |
|     function isObject(obj) {
 | |
|         return Object.prototype.toString.call(obj) === "[object Object]";
 | |
|     }
 | |
| 
 | |
|     // findLast
 | |
|     function findLast(array, callback) {
 | |
|         var index = array.length;
 | |
| 
 | |
|         while (index -= 1) {
 | |
|             if (callback(array[index])) { return array[index]; }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // find
 | |
|     function find(array, callback) {
 | |
|         var index = 0;
 | |
| 
 | |
|         var max = array && array.length || 0;
 | |
| 
 | |
|         var match;
 | |
| 
 | |
|         if (typeof callback !== "function") {
 | |
|             match = callback;
 | |
|             callback = function (item) {
 | |
|                 return item === match;
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         while (index < max) {
 | |
|             if (callback(array[index])) { return array[index]; }
 | |
|             index += 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // each
 | |
|     function each(array, callback) {
 | |
|         var index = 0,
 | |
|             max = array.length;
 | |
| 
 | |
|         if (!array || !max) { return; }
 | |
| 
 | |
|         while (index < max) {
 | |
|             if (callback(array[index], index) === false) { return; }
 | |
|             index += 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // map
 | |
|     function map(array, callback) {
 | |
|         var index = 0,
 | |
|             max = array.length,
 | |
|             ret = [];
 | |
| 
 | |
|         if (!array || !max) { return ret; }
 | |
| 
 | |
|         while (index < max) {
 | |
|             ret[index] = callback(array[index], index);
 | |
|             index += 1;
 | |
|         }
 | |
| 
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     // pluck
 | |
|     function pluck(array, prop) {
 | |
|         return map(array, function (item) {
 | |
|             return item[prop];
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     // compact
 | |
|     function compact(array) {
 | |
|         var ret = [];
 | |
| 
 | |
|         each(array, function (item) {
 | |
|             if (item) { ret.push(item); }
 | |
|         });
 | |
| 
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     // unique
 | |
|     function unique(array) {
 | |
|         var ret = [];
 | |
| 
 | |
|         each(array, function (_a) {
 | |
|             if (!find(ret, _a)) { ret.push(_a); }
 | |
|         });
 | |
| 
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     // intersection
 | |
|     function intersection(a, b) {
 | |
|         var ret = [];
 | |
| 
 | |
|         each(a, function (_a) {
 | |
|             each(b, function (_b) {
 | |
|                 if (_a === _b) { ret.push(_a); }
 | |
|             });
 | |
|         });
 | |
| 
 | |
|         return unique(ret);
 | |
|     }
 | |
| 
 | |
|     // rest
 | |
|     function rest(array, callback) {
 | |
|         var ret = [];
 | |
| 
 | |
|         each(array, function (item, index) {
 | |
|             if (!callback(item)) {
 | |
|                 ret = array.slice(index);
 | |
|                 return false;
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     // initial
 | |
|     function initial(array, callback) {
 | |
|         var reversed = array.slice().reverse();
 | |
| 
 | |
|         return rest(reversed, callback).reverse();
 | |
|     }
 | |
| 
 | |
|     // extend
 | |
|     function extend(a, b) {
 | |
|         for (var key in b) {
 | |
|             if (b.hasOwnProperty(key)) { a[key] = b[key]; }
 | |
|         }
 | |
| 
 | |
|         return a;
 | |
|     }
 | |
| 
 | |
|     // keys
 | |
|     function keys(a) {
 | |
|         var ret = [];
 | |
| 
 | |
|         for (var key in a) {
 | |
|             if (a.hasOwnProperty(key)) { ret.push(key); }
 | |
|         }
 | |
| 
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     // any
 | |
|     function any(array, callback) {
 | |
|         var index = 0,
 | |
|             max = array.length;
 | |
| 
 | |
|         if (!array || !max) { return false; }
 | |
| 
 | |
|         while (index < max) {
 | |
|             if (callback(array[index], index) === true) { return true; }
 | |
|             index += 1;
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // flatten
 | |
|     function flatten(array) {
 | |
|         var ret = [];
 | |
| 
 | |
|         each(array, function(child) {
 | |
|             ret = ret.concat(child);
 | |
|         });
 | |
| 
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     function toLocaleStringSupportsLocales() {
 | |
|         var number = 0;
 | |
|         try {
 | |
|             number.toLocaleString('i');
 | |
|         } catch (e) {
 | |
|             return e.name === 'RangeError';
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     function featureTestFormatterRounding(formatter) {
 | |
|         return formatter(3.55, "en", {
 | |
|             useGrouping: false,
 | |
|             minimumIntegerDigits: 1,
 | |
|             minimumFractionDigits: 1,
 | |
|             maximumFractionDigits: 1
 | |
|         }) === "3.6";
 | |
|     }
 | |
| 
 | |
|     function featureTestFormatter(formatter) {
 | |
|         var passed = true;
 | |
| 
 | |
|         // Test minimumIntegerDigits.
 | |
|         passed = passed && formatter(1, "en", { minimumIntegerDigits: 1 }) === "1";
 | |
|         passed = passed && formatter(1, "en", { minimumIntegerDigits: 2 }) === "01";
 | |
|         passed = passed && formatter(1, "en", { minimumIntegerDigits: 3 }) === "001";
 | |
|         if (!passed) { return false; }
 | |
| 
 | |
|         // Test maximumFractionDigits and minimumFractionDigits.
 | |
|         passed = passed && formatter(99.99, "en", { maximumFractionDigits: 0, minimumFractionDigits: 0 }) === "100";
 | |
|         passed = passed && formatter(99.99, "en", { maximumFractionDigits: 1, minimumFractionDigits: 1 }) === "100.0";
 | |
|         passed = passed && formatter(99.99, "en", { maximumFractionDigits: 2, minimumFractionDigits: 2 }) === "99.99";
 | |
|         passed = passed && formatter(99.99, "en", { maximumFractionDigits: 3, minimumFractionDigits: 3 }) === "99.990";
 | |
|         if (!passed) { return false; }
 | |
| 
 | |
|         // Test maximumSignificantDigits.
 | |
|         passed = passed && formatter(99.99, "en", { maximumSignificantDigits: 1 }) === "100";
 | |
|         passed = passed && formatter(99.99, "en", { maximumSignificantDigits: 2 }) === "100";
 | |
|         passed = passed && formatter(99.99, "en", { maximumSignificantDigits: 3 }) === "100";
 | |
|         passed = passed && formatter(99.99, "en", { maximumSignificantDigits: 4 }) === "99.99";
 | |
|         passed = passed && formatter(99.99, "en", { maximumSignificantDigits: 5 }) === "99.99";
 | |
|         if (!passed) { return false; }
 | |
| 
 | |
|         // Test grouping.
 | |
|         passed = passed && formatter(1000, "en", { useGrouping: true }) === "1,000";
 | |
|         passed = passed && formatter(1000, "en", { useGrouping: false }) === "1000";
 | |
|         if (!passed) { return false; }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     // durationsFormat(durations [, template] [, precision] [, settings])
 | |
|     function durationsFormat() {
 | |
|         var args = [].slice.call(arguments);
 | |
|         var settings = {};
 | |
|         var durations;
 | |
| 
 | |
|         // Parse arguments.
 | |
|         each(args, function (arg, index) {
 | |
|             if (!index) {
 | |
|                 if (!isArray(arg)) {
 | |
|                     throw "Expected array as the first argument to durationsFormat.";
 | |
|                 }
 | |
| 
 | |
|                 durations = arg;
 | |
|             }
 | |
| 
 | |
|             if (typeof arg === "string" || typeof arg === "function") {
 | |
|                 settings.template = arg;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (typeof arg === "number") {
 | |
|                 settings.precision = arg;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (isObject(arg)) {
 | |
|                 extend(settings, arg);
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         if (!durations || !durations.length) {
 | |
|             return [];
 | |
|         }
 | |
| 
 | |
|         settings.returnMomentTypes = true;
 | |
| 
 | |
|         var formattedDurations = map(durations, function (dur) {
 | |
|             return dur.format(settings);
 | |
|         });
 | |
| 
 | |
|         // Merge token types from all durations.
 | |
|         var outputTypes = intersection(types, unique(pluck(flatten(formattedDurations), "type")));
 | |
| 
 | |
|         var largest = settings.largest;
 | |
| 
 | |
|         if (largest) {
 | |
|             outputTypes = outputTypes.slice(0, largest);
 | |
|         }
 | |
| 
 | |
|         settings.returnMomentTypes = false;
 | |
|         settings.outputTypes = outputTypes;
 | |
| 
 | |
|         return map(durations, function (dur) {
 | |
|             return dur.format(settings);
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     // durationFormat([template] [, precision] [, settings])
 | |
|     function durationFormat() {
 | |
| 
 | |
|         var args = [].slice.call(arguments);
 | |
|         var settings = extend({}, this.format.defaults);
 | |
| 
 | |
|         // Keep a shadow copy of this moment for calculating remainders.
 | |
|         // Perform all calculations on positive duration value, handle negative
 | |
|         // sign at the very end.
 | |
|         var asMilliseconds = this.asMilliseconds();
 | |
|         var asMonths = this.asMonths();
 | |
| 
 | |
|         // Treat invalid durations as having a value of 0 milliseconds.
 | |
|         if (typeof this.isValid === "function" && this.isValid() === false) {
 | |
|             asMilliseconds = 0;
 | |
|             asMonths = 0;
 | |
|         }
 | |
| 
 | |
|         var isNegative = asMilliseconds < 0;
 | |
| 
 | |
|         // Two shadow copies are needed because of the way moment.js handles
 | |
|         // duration arithmetic for years/months and for weeks/days/hours/minutes/seconds.
 | |
|         var remainder = moment.duration(Math.abs(asMilliseconds), "milliseconds");
 | |
|         var remainderMonths = moment.duration(Math.abs(asMonths), "months");
 | |
| 
 | |
|         // Parse arguments.
 | |
|         each(args, function (arg) {
 | |
|             if (typeof arg === "string" || typeof arg === "function") {
 | |
|                 settings.template = arg;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (typeof arg === "number") {
 | |
|                 settings.precision = arg;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (isObject(arg)) {
 | |
|                 extend(settings, arg);
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         var momentTokens = {
 | |
|             years: "y",
 | |
|             months: "M",
 | |
|             weeks: "w",
 | |
|             days: "d",
 | |
|             hours: "h",
 | |
|             minutes: "m",
 | |
|             seconds: "s",
 | |
|             milliseconds: "S"
 | |
|         };
 | |
| 
 | |
|         var tokenDefs = {
 | |
|             escape: /\[(.+?)\]/,
 | |
|             years: /\*?[Yy]+/,
 | |
|             months: /\*?M+/,
 | |
|             weeks: /\*?[Ww]+/,
 | |
|             days: /\*?[Dd]+/,
 | |
|             hours: /\*?[Hh]+/,
 | |
|             minutes: /\*?m+/,
 | |
|             seconds: /\*?s+/,
 | |
|             milliseconds: /\*?S+/,
 | |
|             general: /.+?/
 | |
|         };
 | |
| 
 | |
|         // Types array is available in the template function.
 | |
|         settings.types = types;
 | |
| 
 | |
|         var typeMap = function (token) {
 | |
|             return find(types, function (type) {
 | |
|                 return tokenDefs[type].test(token);
 | |
|             });
 | |
|         };
 | |
| 
 | |
|         var tokenizer = new RegExp(map(types, function (type) {
 | |
|             return tokenDefs[type].source;
 | |
|         }).join("|"), "g");
 | |
| 
 | |
|         // Current duration object is available in the template function.
 | |
|         settings.duration = this;
 | |
| 
 | |
|         // Eval template function and cache template string.
 | |
|         var template = typeof settings.template === "function" ? settings.template.apply(settings) : settings.template;
 | |
| 
 | |
|         // outputTypes and returnMomentTypes are settings to support durationsFormat().
 | |
| 
 | |
|         // outputTypes is an array of moment token types that determines
 | |
|         // the tokens returned in formatted output. This option overrides
 | |
|         // trim, largest, stopTrim, etc.
 | |
|         var outputTypes = settings.outputTypes;
 | |
| 
 | |
|         // returnMomentTypes is a boolean that sets durationFormat to return
 | |
|         // the processed momentTypes instead of formatted output.
 | |
|         var returnMomentTypes = settings.returnMomentTypes;
 | |
| 
 | |
|         var largest = settings.largest;
 | |
| 
 | |
|         // Setup stopTrim array of token types.
 | |
|         var stopTrim = [];
 | |
| 
 | |
|         if (!outputTypes) {
 | |
|             if (isArray(settings.stopTrim)) {
 | |
|                 settings.stopTrim = settings.stopTrim.join("");
 | |
|             }
 | |
| 
 | |
|             // Parse stopTrim string to create token types array.
 | |
|             if (settings.stopTrim) {
 | |
|                 each(settings.stopTrim.match(tokenizer), function (token) {
 | |
|                     var type = typeMap(token);
 | |
| 
 | |
|                     if (type === "escape" || type === "general") {
 | |
|                         return;
 | |
|                     }
 | |
| 
 | |
|                     stopTrim.push(type);
 | |
|                 });
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Cache moment's locale data.
 | |
|         var localeData = moment.localeData();
 | |
| 
 | |
|         if (!localeData) {
 | |
|             localeData = {};
 | |
|         }
 | |
| 
 | |
|         // Fall back to this plugin's `eng` extension.
 | |
|         each(keys(engLocale), function (key) {
 | |
|             if (typeof engLocale[key] === "function") {
 | |
|                 if (!localeData[key]) {
 | |
|                     localeData[key] = engLocale[key];
 | |
|                 }
 | |
| 
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (!localeData["_" + key]) {
 | |
|                 localeData["_" + key] = engLocale[key];
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         // Replace Duration Time Template strings.
 | |
|         // For locale `eng`: `_HMS_`, `_HM_`, and `_MS_`.
 | |
|         each(keys(localeData._durationTimeTemplates), function (item) {
 | |
|             template = template.replace("_" + item + "_", localeData._durationTimeTemplates[item]);
 | |
|         });
 | |
| 
 | |
|         // Determine user's locale.
 | |
|         var userLocale = settings.userLocale || moment.locale();
 | |
| 
 | |
|         var useLeftUnits = settings.useLeftUnits;
 | |
|         var usePlural = settings.usePlural;
 | |
|         var precision = settings.precision;
 | |
|         var forceLength = settings.forceLength;
 | |
|         var useGrouping = settings.useGrouping;
 | |
|         var trunc = settings.trunc;
 | |
| 
 | |
|         // Use significant digits only when precision is greater than 0.
 | |
|         var useSignificantDigits = settings.useSignificantDigits && precision > 0;
 | |
|         var significantDigits = useSignificantDigits ? settings.precision : 0;
 | |
|         var significantDigitsCache = significantDigits;
 | |
| 
 | |
|         var minValue = settings.minValue;
 | |
|         var isMinValue = false;
 | |
| 
 | |
|         var maxValue = settings.maxValue;
 | |
|         var isMaxValue = false;
 | |
| 
 | |
|         // formatNumber fallback options.
 | |
|         var useToLocaleString = settings.useToLocaleString;
 | |
|         var groupingSeparator = settings.groupingSeparator;
 | |
|         var decimalSeparator = settings.decimalSeparator;
 | |
|         var grouping = settings.grouping;
 | |
| 
 | |
|         useToLocaleString = useToLocaleString && (toLocaleStringWorks || intlNumberFormatWorks);
 | |
| 
 | |
|         // Trim options.
 | |
|         var trim = settings.trim;
 | |
| 
 | |
|         if (isArray(trim)) {
 | |
|             trim = trim.join(" ");
 | |
|         }
 | |
| 
 | |
|         if (trim === null && (largest || maxValue || useSignificantDigits)) {
 | |
|             trim = "all";
 | |
|         }
 | |
| 
 | |
|         if (trim === null || trim === true || trim === "left" || trim === "right") {
 | |
|             trim = "large";
 | |
|         }
 | |
| 
 | |
|         if (trim === false) {
 | |
|             trim = "";
 | |
|         }
 | |
| 
 | |
|         var trimIncludes = function (item) {
 | |
|             return item.test(trim);
 | |
|         };
 | |
| 
 | |
|         var rLarge = /large/;
 | |
|         var rSmall = /small/;
 | |
|         var rBoth = /both/;
 | |
|         var rMid = /mid/;
 | |
|         var rAll = /^all|[^sm]all/;
 | |
|         var rFinal = /final/;
 | |
| 
 | |
|         var trimLarge = largest > 0 || any([rLarge, rBoth, rAll], trimIncludes);
 | |
|         var trimSmall = any([rSmall, rBoth, rAll], trimIncludes);
 | |
|         var trimMid = any([rMid, rAll], trimIncludes);
 | |
|         var trimFinal = any([rFinal, rAll], trimIncludes);
 | |
| 
 | |
|         // Parse format string to create raw tokens array.
 | |
|         var rawTokens = map(template.match(tokenizer), function (token, index) {
 | |
|             var type = typeMap(token);
 | |
| 
 | |
|             if (token.slice(0, 1) === "*") {
 | |
|                 token = token.slice(1);
 | |
| 
 | |
|                 if (type !== "escape" && type !== "general") {
 | |
|                     stopTrim.push(type);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return {
 | |
|                 index: index,
 | |
|                 length: token.length,
 | |
|                 text: "",
 | |
| 
 | |
|                 // Replace escaped tokens with the non-escaped token text.
 | |
|                 token: (type === "escape" ? token.replace(tokenDefs.escape, "$1") : token),
 | |
| 
 | |
|                 // Ignore type on non-moment tokens.
 | |
|                 type: ((type === "escape" || type === "general") ? null : type)
 | |
|             };
 | |
|         });
 | |
| 
 | |
|         // Associate text tokens with moment tokens.
 | |
|         var currentToken = {
 | |
|             index: 0,
 | |
|             length: 0,
 | |
|             token: "",
 | |
|             text: "",
 | |
|             type: null
 | |
|         };
 | |
| 
 | |
|         var tokens = [];
 | |
| 
 | |
|         if (useLeftUnits) {
 | |
|             rawTokens.reverse();
 | |
|         }
 | |
| 
 | |
|         each(rawTokens, function (token) {
 | |
|             if (token.type) {
 | |
|                 if (currentToken.type || currentToken.text) {
 | |
|                     tokens.push(currentToken);
 | |
|                 }
 | |
| 
 | |
|                 currentToken = token;
 | |
| 
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (useLeftUnits) {
 | |
|                 currentToken.text = token.token + currentToken.text;
 | |
|             } else {
 | |
|                 currentToken.text += token.token;
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         if (currentToken.type || currentToken.text) {
 | |
|             tokens.push(currentToken);
 | |
|         }
 | |
| 
 | |
|         if (useLeftUnits) {
 | |
|             tokens.reverse();
 | |
|         }
 | |
| 
 | |
|         // Find unique moment token types in the template in order of
 | |
|         // descending magnitude.
 | |
|         var momentTypes = intersection(types, unique(compact(pluck(tokens, "type"))));
 | |
| 
 | |
|         // Exit early if there are no moment token types.
 | |
|         if (!momentTypes.length) {
 | |
|             return pluck(tokens, "text").join("");
 | |
|         }
 | |
| 
 | |
|         // Calculate values for each moment type in the template.
 | |
|         // For processing the settings, values are associated with moment types.
 | |
|         // Values will be assigned to tokens at the last step in order to
 | |
|         // assume nothing about frequency or order of tokens in the template.
 | |
|         momentTypes = map(momentTypes, function (momentType, index) {
 | |
|             // Is this the least-magnitude moment token found?
 | |
|             var isSmallest = ((index + 1) === momentTypes.length);
 | |
| 
 | |
|             // Is this the greatest-magnitude moment token found?
 | |
|             var isLargest = (!index);
 | |
| 
 | |
|             // Get the raw value in the current units.
 | |
|             var rawValue;
 | |
| 
 | |
|             if (momentType === "years" || momentType === "months") {
 | |
|                 rawValue = remainderMonths.as(momentType);
 | |
|             } else {
 | |
|                 rawValue = remainder.as(momentType);
 | |
|             }
 | |
| 
 | |
|             var wholeValue = Math.floor(rawValue);
 | |
|             var decimalValue = rawValue - wholeValue;
 | |
| 
 | |
|             var token = find(tokens, function (token) {
 | |
|                 return momentType === token.type;
 | |
|             });
 | |
| 
 | |
|             if (isLargest && maxValue && rawValue > maxValue) {
 | |
|                 isMaxValue = true;
 | |
|             }
 | |
| 
 | |
|             if (isSmallest && minValue && Math.abs(settings.duration.as(momentType)) < minValue) {
 | |
|                 isMinValue = true;
 | |
|             }
 | |
| 
 | |
|             // Note the length of the largest-magnitude moment token:
 | |
|             // if it is greater than one and forceLength is not set,
 | |
|             // then default forceLength to `true`.
 | |
|             //
 | |
|             // Rationale is this: If the template is "h:mm:ss" and the
 | |
|             // moment value is 5 minutes, the user-friendly output is
 | |
|             // "5:00", not "05:00". We shouldn't pad the `minutes` token
 | |
|             // even though it has length of two if the template is "h:mm:ss";
 | |
|             //
 | |
|             // If the minutes output should always include the leading zero
 | |
|             // even when the hour is trimmed then set `{ forceLength: true }`
 | |
|             // to output "05:00". If the template is "hh:mm:ss", the user
 | |
|             // clearly wanted everything padded so we should output "05:00";
 | |
|             //
 | |
|             // If the user wants the full padded output, they can use
 | |
|             // template "hh:mm:ss" and set `{ trim: false }` to output
 | |
|             // "00:05:00".
 | |
|             if (isLargest && forceLength === null && token.length > 1) {
 | |
|                 forceLength = true;
 | |
|             }
 | |
| 
 | |
|             // Update remainder.
 | |
|             remainder.subtract(wholeValue, momentType);
 | |
|             remainderMonths.subtract(wholeValue, momentType);
 | |
| 
 | |
|             return {
 | |
|                 rawValue: rawValue,
 | |
|                 wholeValue: wholeValue,
 | |
|                 // Decimal value is only retained for the least-magnitude
 | |
|                 // moment type in the format template.
 | |
|                 decimalValue: isSmallest ? decimalValue : 0,
 | |
|                 isSmallest: isSmallest,
 | |
|                 isLargest: isLargest,
 | |
|                 type: momentType,
 | |
|                 // Tokens can appear multiple times in a template string,
 | |
|                 // but all instances must share the same length.
 | |
|                 tokenLength: token.length
 | |
|             };
 | |
|         });
 | |
| 
 | |
|         var truncMethod = trunc ? Math.floor : Math.round;
 | |
|         var truncate = function (value, places) {
 | |
|             var factor = Math.pow(10, places);
 | |
|             return truncMethod(value * factor) / factor;
 | |
|         };
 | |
| 
 | |
|         var foundFirst = false;
 | |
|         var bubbled = false;
 | |
| 
 | |
|         var formatValue = function (momentType, index) {
 | |
|             var formatOptions = {
 | |
|                 useGrouping: useGrouping,
 | |
|                 groupingSeparator: groupingSeparator,
 | |
|                 decimalSeparator: decimalSeparator,
 | |
|                 grouping: grouping,
 | |
|                 useToLocaleString: useToLocaleString
 | |
|             };
 | |
| 
 | |
|             if (useSignificantDigits) {
 | |
|                 if (significantDigits <= 0) {
 | |
|                     momentType.rawValue = 0;
 | |
|                     momentType.wholeValue = 0;
 | |
|                     momentType.decimalValue = 0;
 | |
|                 } else {
 | |
|                     formatOptions.maximumSignificantDigits = significantDigits;
 | |
|                     momentType.significantDigits = significantDigits;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (isMaxValue && !bubbled) {
 | |
|                 if (momentType.isLargest) {
 | |
|                     momentType.wholeValue = maxValue;
 | |
|                     momentType.decimalValue = 0;
 | |
|                 } else {
 | |
|                     momentType.wholeValue = 0;
 | |
|                     momentType.decimalValue = 0;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (isMinValue && !bubbled) {
 | |
|                 if (momentType.isSmallest) {
 | |
|                     momentType.wholeValue = minValue;
 | |
|                     momentType.decimalValue = 0;
 | |
|                 } else {
 | |
|                     momentType.wholeValue = 0;
 | |
|                     momentType.decimalValue = 0;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (momentType.isSmallest || momentType.significantDigits && momentType.significantDigits - momentType.wholeValue.toString().length <= 0) {
 | |
|                 // Apply precision to least significant token value.
 | |
|                 if (precision < 0) {
 | |
|                     momentType.value = truncate(momentType.wholeValue, precision);
 | |
|                 } else if (precision === 0) {
 | |
|                     momentType.value = truncMethod(momentType.wholeValue + momentType.decimalValue);
 | |
|                 } else { // precision > 0
 | |
|                     if (useSignificantDigits) {
 | |
|                         if (trunc) {
 | |
|                             momentType.value = truncate(momentType.rawValue, significantDigits - momentType.wholeValue.toString().length);
 | |
|                         } else {
 | |
|                             momentType.value = momentType.rawValue;
 | |
|                         }
 | |
| 
 | |
|                         if (momentType.wholeValue) {
 | |
|                             significantDigits -= momentType.wholeValue.toString().length;
 | |
|                         }
 | |
|                     } else {
 | |
|                         formatOptions.fractionDigits = precision;
 | |
| 
 | |
|                         if (trunc) {
 | |
|                             momentType.value = momentType.wholeValue + truncate(momentType.decimalValue, precision);
 | |
|                         } else {
 | |
|                             momentType.value = momentType.wholeValue + momentType.decimalValue;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             } else {
 | |
|                 if (useSignificantDigits && momentType.wholeValue) {
 | |
|                     // Outer Math.round required here to handle floating point errors.
 | |
|                     momentType.value = Math.round(truncate(momentType.wholeValue, momentType.significantDigits - momentType.wholeValue.toString().length));
 | |
| 
 | |
|                     significantDigits -= momentType.wholeValue.toString().length;
 | |
|                 } else {
 | |
|                     momentType.value = momentType.wholeValue;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (momentType.tokenLength > 1 && (forceLength || foundFirst)) {
 | |
|                 formatOptions.minimumIntegerDigits = momentType.tokenLength;
 | |
| 
 | |
|                 if (bubbled && formatOptions.maximumSignificantDigits < momentType.tokenLength) {
 | |
|                     delete formatOptions.maximumSignificantDigits;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (!foundFirst && (momentType.value > 0 || trim === "" /* trim: false */ || find(stopTrim, momentType.type) || find(outputTypes, momentType.type))) {
 | |
|                 foundFirst = true;
 | |
|             }
 | |
| 
 | |
|             momentType.formattedValue = formatNumber(momentType.value, formatOptions, userLocale);
 | |
| 
 | |
|             formatOptions.useGrouping = false;
 | |
|             formatOptions.decimalSeparator = ".";
 | |
|             momentType.formattedValueEn = formatNumber(momentType.value, formatOptions, "en");
 | |
| 
 | |
|             if (momentType.tokenLength === 2 && momentType.type === "milliseconds") {
 | |
|                 momentType.formattedValueMS = formatNumber(momentType.value, {
 | |
|                     minimumIntegerDigits: 3,
 | |
|                     useGrouping: false
 | |
|                 }, "en").slice(0, 2);
 | |
|             }
 | |
| 
 | |
|             return momentType;
 | |
|         };
 | |
| 
 | |
|         // Calculate formatted values.
 | |
|         momentTypes = map(momentTypes, formatValue);
 | |
|         momentTypes = compact(momentTypes);
 | |
| 
 | |
|         // Bubble rounded values.
 | |
|         if (momentTypes.length > 1) {
 | |
|             var findType = function (type) {
 | |
|                 return find(momentTypes, function (momentType) {
 | |
|                     return momentType.type === type;
 | |
|                 });
 | |
|             };
 | |
| 
 | |
|             var bubbleTypes = function (bubble) {
 | |
|                 var bubbleMomentType = findType(bubble.type);
 | |
| 
 | |
|                 if (!bubbleMomentType) {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 each(bubble.targets, function (target) {
 | |
|                     var targetMomentType = findType(target.type);
 | |
| 
 | |
|                     if (!targetMomentType) {
 | |
|                         return;
 | |
|                     }
 | |
| 
 | |
|                     if (parseInt(bubbleMomentType.formattedValueEn, 10) === target.value) {
 | |
|                         bubbleMomentType.rawValue = 0;
 | |
|                         bubbleMomentType.wholeValue = 0;
 | |
|                         bubbleMomentType.decimalValue = 0;
 | |
|                         targetMomentType.rawValue += 1;
 | |
|                         targetMomentType.wholeValue += 1;
 | |
|                         targetMomentType.decimalValue = 0;
 | |
|                         targetMomentType.formattedValueEn = targetMomentType.wholeValue.toString();
 | |
|                         bubbled = true;
 | |
|                     }
 | |
|                 });
 | |
|             };
 | |
| 
 | |
|             each(bubbles, bubbleTypes);
 | |
|         }
 | |
| 
 | |
|         // Recalculate formatted values.
 | |
|         if (bubbled) {
 | |
|             foundFirst = false;
 | |
|             significantDigits = significantDigitsCache;
 | |
|             momentTypes = map(momentTypes, formatValue);
 | |
|             momentTypes = compact(momentTypes);
 | |
|         }
 | |
| 
 | |
|         if (outputTypes && !(isMaxValue && !settings.trim)) {
 | |
|             momentTypes = map(momentTypes, function (momentType) {
 | |
|                 if (find(outputTypes, function (outputType) {
 | |
|                     return momentType.type === outputType;
 | |
|                 })) {
 | |
|                     return momentType;
 | |
|                 }
 | |
| 
 | |
|                 return null;
 | |
|             });
 | |
| 
 | |
|             momentTypes = compact(momentTypes);
 | |
|         } else {
 | |
|             // Trim Large.
 | |
|             if (trimLarge) {
 | |
|                 momentTypes = rest(momentTypes, function (momentType) {
 | |
|                     // Stop trimming on:
 | |
|                     // - the smallest moment type
 | |
|                     // - a type marked for stopTrim
 | |
|                     // - a type that has a whole value
 | |
|                     return !momentType.isSmallest && !momentType.wholeValue && !find(stopTrim, momentType.type);
 | |
|                 });
 | |
|             }
 | |
| 
 | |
|             // Largest.
 | |
|             if (largest && momentTypes.length) {
 | |
|                 momentTypes = momentTypes.slice(0, largest);
 | |
|             }
 | |
| 
 | |
|             // Trim Small.
 | |
|             if (trimSmall && momentTypes.length > 1) {
 | |
|                 momentTypes = initial(momentTypes, function (momentType) {
 | |
|                     // Stop trimming on:
 | |
|                     // - a type marked for stopTrim
 | |
|                     // - a type that has a whole value
 | |
|                     // - the largest momentType
 | |
|                     return !momentType.wholeValue && !find(stopTrim, momentType.type) && !momentType.isLargest;
 | |
|                 });
 | |
|             }
 | |
| 
 | |
|             // Trim Mid.
 | |
|             if (trimMid) {
 | |
|                 momentTypes = map(momentTypes, function (momentType, index) {
 | |
|                     if (index > 0 && index < momentTypes.length - 1 && !momentType.wholeValue) {
 | |
|                         return null;
 | |
|                     }
 | |
| 
 | |
|                     return momentType;
 | |
|                 });
 | |
| 
 | |
|                 momentTypes = compact(momentTypes);
 | |
|             }
 | |
| 
 | |
|             // Trim Final.
 | |
|             if (trimFinal && momentTypes.length === 1 && !momentTypes[0].wholeValue && !(!trunc && momentTypes[0].isSmallest && momentTypes[0].rawValue < minValue)) {
 | |
|                 momentTypes = [];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (returnMomentTypes) {
 | |
|             return momentTypes;
 | |
|         }
 | |
| 
 | |
|         // Localize and pluralize unit labels.
 | |
|         each(tokens, function (token) {
 | |
|             var key = momentTokens[token.type];
 | |
| 
 | |
|             var momentType = find(momentTypes, function (momentType) {
 | |
|                 return momentType.type === token.type;
 | |
|             });
 | |
| 
 | |
|             if (!key || !momentType) {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             var values = momentType.formattedValueEn.split(".");
 | |
| 
 | |
|             values[0] = parseInt(values[0], 10);
 | |
| 
 | |
|             if (values[1]) {
 | |
|                 values[1] = parseFloat("0." + values[1], 10);
 | |
|             } else {
 | |
|                 values[1] = null;
 | |
|             }
 | |
| 
 | |
|             var pluralKey = localeData.durationPluralKey(key, values[0], values[1]);
 | |
| 
 | |
|             var labels = durationGetLabels(key, localeData);
 | |
| 
 | |
|             var autoLocalized = false;
 | |
| 
 | |
|             var pluralizedLabels = {};
 | |
| 
 | |
|             // Auto-Localized unit labels.
 | |
|             each(localeData._durationLabelTypes, function (labelType) {
 | |
|                 var label = find(labels, function (label) {
 | |
|                     return label.type === labelType.type && label.key === pluralKey;
 | |
|                 });
 | |
| 
 | |
|                 if (label) {
 | |
|                     pluralizedLabels[label.type] = label.label;
 | |
| 
 | |
|                     if (stringIncludes(token.text, labelType.string)) {
 | |
|                         token.text = token.text.replace(labelType.string, label.label);
 | |
|                         autoLocalized = true;
 | |
|                     }
 | |
|                 }
 | |
|             });
 | |
| 
 | |
|             // Auto-pluralized unit labels.
 | |
|             if (usePlural && !autoLocalized) {
 | |
|                 labels.sort(durationLabelCompare);
 | |
| 
 | |
|                 each(labels, function (label) {
 | |
|                     if (pluralizedLabels[label.type] === label.label) {
 | |
|                         if (stringIncludes(token.text, label.label)) {
 | |
|                             // Stop checking this token if its label is already
 | |
|                             // correctly pluralized.
 | |
|                             return false;
 | |
|                         }
 | |
| 
 | |
|                         // Skip this label if it is correct, but not present in
 | |
|                         // the token's text.
 | |
|                         return;
 | |
|                     }
 | |
| 
 | |
|                     if (stringIncludes(token.text, label.label)) {
 | |
|                         // Replece this token's label and stop checking.
 | |
|                         token.text = token.text.replace(label.label, pluralizedLabels[label.type]);
 | |
|                         return false;
 | |
|                     }
 | |
|                 });
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         // Build ouptut.
 | |
|         tokens = map(tokens, function (token) {
 | |
|             if (!token.type) {
 | |
|                 return token.text;
 | |
|             }
 | |
| 
 | |
|             var momentType = find(momentTypes, function (momentType) {
 | |
|                 return momentType.type === token.type;
 | |
|             });
 | |
| 
 | |
|             if (!momentType) {
 | |
|                 return "";
 | |
|             }
 | |
| 
 | |
|             var out = "";
 | |
| 
 | |
|             if (useLeftUnits) {
 | |
|                 out += token.text;
 | |
|             }
 | |
| 
 | |
|             if (isNegative && isMaxValue || !isNegative && isMinValue) {
 | |
|                 out += "< ";
 | |
|                 isMaxValue = false;
 | |
|                 isMinValue = false;
 | |
|             }
 | |
| 
 | |
|             if (isNegative && isMinValue || !isNegative && isMaxValue) {
 | |
|                 out += "> ";
 | |
|                 isMaxValue = false;
 | |
|                 isMinValue = false;
 | |
|             }
 | |
| 
 | |
|             if (isNegative && (momentType.value > 0 || trim === "" || find(stopTrim, momentType.type) || find(outputTypes, momentType.type))) {
 | |
|                 out += "-";
 | |
|                 isNegative = false;
 | |
|             }
 | |
| 
 | |
|             if (token.type === "milliseconds" && momentType.formattedValueMS) {
 | |
|                 out += momentType.formattedValueMS;
 | |
|             } else {
 | |
|                 out += momentType.formattedValue;
 | |
|             }
 | |
| 
 | |
|             if (!useLeftUnits) {
 | |
|                 out += token.text;
 | |
|             }
 | |
| 
 | |
|             return out;
 | |
|         });
 | |
| 
 | |
|         // Trim leading and trailing comma, space, colon, and dot.
 | |
|         return tokens.join("").replace(/(,| |:|\.)*$/, "").replace(/^(,| |:|\.)*/, "");
 | |
|     }
 | |
| 
 | |
|     // defaultFormatTemplate
 | |
|     function defaultFormatTemplate() {
 | |
|         var dur = this.duration;
 | |
| 
 | |
|         var findType = function findType(type) {
 | |
|             return dur._data[type];
 | |
|         };
 | |
| 
 | |
|         var firstType = find(this.types, findType);
 | |
| 
 | |
|         var lastType = findLast(this.types, findType);
 | |
| 
 | |
|         // Default template strings for each duration dimension type.
 | |
|         switch (firstType) {
 | |
|             case "milliseconds":
 | |
|                 return "S __";
 | |
|             case "seconds": // Fallthrough.
 | |
|             case "minutes":
 | |
|                 return "*_MS_";
 | |
|             case "hours":
 | |
|                 return "_HMS_";
 | |
|             case "days": // Possible Fallthrough.
 | |
|                 if (firstType === lastType) {
 | |
|                     return "d __";
 | |
|                 }
 | |
|             case "weeks":
 | |
|                 if (firstType === lastType) {
 | |
|                     return "w __";
 | |
|                 }
 | |
| 
 | |
|                 if (this.trim === null) {
 | |
|                     this.trim = "both";
 | |
|                 }
 | |
| 
 | |
|                 return "w __, d __, h __";
 | |
|             case "months": // Possible Fallthrough.
 | |
|                 if (firstType === lastType) {
 | |
|                     return "M __";
 | |
|                 }
 | |
|             case "years":
 | |
|                 if (firstType === lastType) {
 | |
|                     return "y __";
 | |
|                 }
 | |
| 
 | |
|                 if (this.trim === null) {
 | |
|                     this.trim = "both";
 | |
|                 }
 | |
| 
 | |
|                 return "y __, M __, d __";
 | |
|             default:
 | |
|                 if (this.trim === null) {
 | |
|                     this.trim = "both";
 | |
|                 }
 | |
| 
 | |
|                 return "y __, d __, h __, m __, s __";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // init
 | |
|     function init(context) {
 | |
|         if (!context) {
 | |
|             throw "Moment Duration Format init cannot find moment instance.";
 | |
|         }
 | |
| 
 | |
|         context.duration.format = durationsFormat;
 | |
|         context.duration.fn.format = durationFormat;
 | |
| 
 | |
|         context.duration.fn.format.defaults = {
 | |
|             // Many options are defaulted to `null` to distinguish between
 | |
|             // 'not set' and 'set to `false`'
 | |
| 
 | |
|             // trim
 | |
|             // Can be a string, a delimited list of strings, an array of strings,
 | |
|             // or a boolean.
 | |
|             // "large" - will trim largest-magnitude zero-value tokens until
 | |
|             // finding a token with a value, a token identified as 'stopTrim', or
 | |
|             // the final token of the format string.
 | |
|             // "small" - will trim smallest-magnitude zero-value tokens until
 | |
|             // finding a token with a value, a token identified as 'stopTrim', or
 | |
|             // the final token of the format string.
 | |
|             // "both" - will execute "large" trim then "small" trim.
 | |
|             // "mid" - will trim any zero-value tokens that are not the first or
 | |
|             // last tokens. Usually used in conjunction with "large" or "both".
 | |
|             // e.g. "large mid" or "both mid".
 | |
|             // "final" - will trim the final token if it is zero-value. Use this
 | |
|             // option with "large" or "both" to output an empty string when
 | |
|             // formatting a zero-value duration. e.g. "large final" or "both final".
 | |
|             // "all" - Will trim all zero-value tokens. Shorthand for "both mid final".
 | |
|             // "left" - maps to "large" to support plugin's version 1 API.
 | |
|             // "right" - maps to "large" to support plugin's version 1 API.
 | |
|             // `false` - template tokens are not trimmed.
 | |
|             // `true` - treated as "large".
 | |
|             // `null` - treated as "large".
 | |
|             trim: null,
 | |
| 
 | |
|             // stopTrim
 | |
|             // A moment token string, a delimited set of moment token strings,
 | |
|             // or an array of moment token strings. Trimming will stop when a token
 | |
|             // listed in this option is reached. A "*" character in the format
 | |
|             // template string will also mark a moment token as stopTrim.
 | |
|             // e.g. "d [days] *h:mm:ss" will always stop trimming at the 'hours' token.
 | |
|             stopTrim: null,
 | |
| 
 | |
|             // largest
 | |
|             // Set to a positive integer to output only the "n" largest-magnitude
 | |
|             // moment tokens that have a value. All lesser-magnitude moment tokens
 | |
|             // will be ignored. This option takes effect even if `trim` is set
 | |
|             // to `false`.
 | |
|             largest: null,
 | |
| 
 | |
|             // maxValue
 | |
|             // Use `maxValue` to render generalized output for large duration values,
 | |
|             // e.g. `"> 60 days"`. `maxValue` must be a positive integer and is
 | |
|             /// applied to the greatest-magnitude moment token in the format template.
 | |
|             maxValue: null,
 | |
| 
 | |
|             // minValue
 | |
|             // Use `minValue` to render generalized output for small duration values,
 | |
|             // e.g. `"< 5 minutes"`. `minValue` must be a positive integer and is
 | |
|             // applied to the least-magnitude moment token in the format template.
 | |
|             minValue: null,
 | |
| 
 | |
|             // precision
 | |
|             // If a positive integer, number of decimal fraction digits to render.
 | |
|             // If a negative integer, number of integer place digits to truncate to 0.
 | |
|             // If `useSignificantDigits` is set to `true` and `precision` is a positive
 | |
|             // integer, sets the maximum number of significant digits used in the
 | |
|             // formatted output.
 | |
|             precision: 0,
 | |
| 
 | |
|             // trunc
 | |
|             // Default behavior rounds final token value. Set to `true` to
 | |
|             // truncate final token value, which was the default behavior in
 | |
|             // version 1 of this plugin.
 | |
|             trunc: false,
 | |
| 
 | |
|             // forceLength
 | |
|             // Force first moment token with a value to render at full length
 | |
|             // even when template is trimmed and first moment token has length of 1.
 | |
|             forceLength: null,
 | |
| 
 | |
|             // userLocale
 | |
|             // Formatted numerical output is rendered using `toLocaleString`
 | |
|             // and the locale of the user's environment. Set this option to render
 | |
|             // numerical output using a different locale. Unit names are rendered
 | |
|             // and detected using the locale set in moment.js, which can be different
 | |
|             // from the locale of user's environment.
 | |
|             userLocale: null,
 | |
| 
 | |
|             // usePlural
 | |
|             // Will automatically singularize or pluralize unit names when they
 | |
|             // appear in the text associated with each moment token. Standard and
 | |
|             // short unit labels are singularized and pluralized, based on locale.
 | |
|             // e.g. in english, "1 second" or "1 sec" would be rendered instead
 | |
|             // of "1 seconds" or "1 secs". The default pluralization function
 | |
|             // renders a plural label for a value with decimal precision.
 | |
|             // e.g. "1.0 seconds" is never rendered as "1.0 second".
 | |
|             // Label types and pluralization function are configurable in the
 | |
|             // localeData extensions.
 | |
|             usePlural: true,
 | |
| 
 | |
|             // useLeftUnits
 | |
|             // The text to the right of each moment token in a format string
 | |
|             // is treated as that token's units for the purposes of trimming,
 | |
|             // singularizing, and auto-localizing.
 | |
|             // e.g. "h [hours], m [minutes], s [seconds]".
 | |
|             // To properly singularize or localize a format string such as
 | |
|             // "[hours] h, [minutes] m, [seconds] s", where the units appear
 | |
|             // to the left of each moment token, set useLeftUnits to `true`.
 | |
|             // This plugin is not tested in the context of rtl text.
 | |
|             useLeftUnits: false,
 | |
| 
 | |
|             // useGrouping
 | |
|             // Enables locale-based digit grouping in the formatted output. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
 | |
|             useGrouping: true,
 | |
| 
 | |
|             // useSignificantDigits
 | |
|             // Treat the `precision` option as the maximum significant digits
 | |
|             // to be rendered. Precision must be a positive integer. Significant
 | |
|             // digits extend across unit types,
 | |
|             // e.g. "6 hours 37.5 minutes" represents 4 significant digits.
 | |
|             // Enabling this option causes token length to be ignored. See  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
 | |
|             useSignificantDigits: false,
 | |
| 
 | |
|             // template
 | |
|             // The template string used to format the duration. May be a function
 | |
|             // or a string. Template functions are executed with the `this` binding
 | |
|             // of the settings object so that template strings may be dynamically
 | |
|             // generated based on the duration object (accessible via `this.duration`)
 | |
|             // or any of the other settings. Leading and trailing space, comma,
 | |
|             // period, and colon characters are trimmed from the resulting string.
 | |
|             template: defaultFormatTemplate,
 | |
| 
 | |
|             // useToLocaleString
 | |
|             // Set this option to `false` to ignore the `toLocaleString` feature
 | |
|             // test and force the use of the `formatNumber` fallback function
 | |
|             // included in this plugin.
 | |
|             useToLocaleString: true,
 | |
| 
 | |
|             // formatNumber fallback options.
 | |
|             // When `toLocaleString` is detected and passes the feature test, the
 | |
|             // following options will have no effect: `toLocaleString` will be used
 | |
|             // for formatting and the grouping separator, decimal separator, and
 | |
|             // integer digit grouping will be determined by the user locale.
 | |
| 
 | |
|             // groupingSeparator
 | |
|             // The integer digit grouping separator used when using the fallback
 | |
|             // formatNumber function.
 | |
|             groupingSeparator: ",",
 | |
| 
 | |
|             // decimalSeparator
 | |
|             // The decimal separator used when using the fallback formatNumber
 | |
|             // function.
 | |
|             decimalSeparator: ".",
 | |
| 
 | |
|             // grouping
 | |
|             // The integer digit grouping used when using the fallback formatNumber
 | |
|             // function. Must be an array. The default value of `[3]` gives the
 | |
|             // standard 3-digit thousand/million/billion digit groupings for the
 | |
|             // "en" locale. Setting this option to `[3, 2]` would generate the
 | |
|             // thousand/lakh/crore digit groupings used in the "en-IN" locale.
 | |
|             grouping: [3]
 | |
|         };
 | |
| 
 | |
|         context.updateLocale('en', engLocale);
 | |
|     }
 | |
| 
 | |
|     // Run feature tests for `Number#toLocaleString`.
 | |
|     var toLocaleStringFormatter = function(number, locale, options) {
 | |
|         return number.toLocaleString(locale, options);
 | |
|     };
 | |
| 
 | |
|     toLocaleStringWorks = toLocaleStringSupportsLocales() && featureTestFormatter(toLocaleStringFormatter);
 | |
|     toLocaleStringRoundingWorks = toLocaleStringWorks && featureTestFormatterRounding(toLocaleStringFormatter);
 | |
| 
 | |
|     // Run feature tests for `Intl.NumberFormat#format`.
 | |
|     var intlNumberFormatFormatter = function(number, locale, options) {
 | |
|         if (typeof window !== 'undefined' && window && window.Intl && window.Intl.NumberFormat) {
 | |
|             return window.Intl.NumberFormat(locale, options).format(number);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     intlNumberFormatWorks = featureTestFormatter(intlNumberFormatFormatter);
 | |
|     intlNumberFormatRoundingWorks = intlNumberFormatWorks && featureTestFormatterRounding(intlNumberFormatFormatter);
 | |
| 
 | |
|     // Initialize duration format on the global moment instance.
 | |
|     init(moment);
 | |
| 
 | |
|     // Return the init function so that duration format can be
 | |
|     // initialized on other moment instances.
 | |
|     return init;
 | |
| });
 |