mirror of
https://github.com/nasa/openmct.git
synced 2025-06-20 16:10:23 +00:00
[Plugins] Bring over timeline, clock plugins
WTD-1239
This commit is contained in:
482
platform/features/clock/lib/moment-duration-format.js
Normal file
482
platform/features/clock/lib/moment-duration-format.js
Normal file
@ -0,0 +1,482 @@
|
||||
/*! Moment Duration Format v1.3.0
|
||||
* https://github.com/jsmreese/moment-duration-format
|
||||
* Date: 2014-07-15
|
||||
*
|
||||
* Duration format plugin function for the Moment.js library
|
||||
* http://momentjs.com/
|
||||
*
|
||||
* Copyright 2014 John Madhavan-Reese
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
(function (root, undefined) {
|
||||
|
||||
// repeatZero(qty)
|
||||
// returns "0" repeated qty times
|
||||
function repeatZero(qty) {
|
||||
var result = "";
|
||||
|
||||
// exit early
|
||||
// if qty is 0 or a negative number
|
||||
// or doesn't coerce to an integer
|
||||
qty = parseInt(qty, 10);
|
||||
if (!qty || qty < 1) { return result; }
|
||||
|
||||
while (qty) {
|
||||
result += "0";
|
||||
qty -= 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// padZero(str, len [, isRight])
|
||||
// pads a string with zeros up to a specified length
|
||||
// will not pad a string if its length is aready
|
||||
// greater than or equal to the specified length
|
||||
// default output pads with zeros on the left
|
||||
// set isRight to `true` to pad with zeros on the right
|
||||
function padZero(str, len, isRight) {
|
||||
if (str == null) { str = ""; }
|
||||
str = "" + str;
|
||||
|
||||
return (isRight ? str : "") + repeatZero(len - str.length) + (isRight ? "" : str);
|
||||
}
|
||||
|
||||
// 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,
|
||||
max = array.length,
|
||||
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;
|
||||
}
|
||||
|
||||
// define internal moment reference
|
||||
var moment;
|
||||
|
||||
if (typeof require === "function") {
|
||||
try { moment = require('moment'); }
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
if (!moment && root.moment) {
|
||||
moment = root.moment;
|
||||
}
|
||||
|
||||
if (!moment) {
|
||||
throw "Moment Duration Format cannot find Moment.js";
|
||||
}
|
||||
|
||||
// moment.duration.format([template] [, precision] [, settings])
|
||||
moment.duration.fn.format = function () {
|
||||
|
||||
var tokenizer, tokens, types, typeMap, momentTypes, foundFirst, trimIndex,
|
||||
args = [].slice.call(arguments),
|
||||
settings = extend({}, this.format.defaults),
|
||||
// keep a shadow copy of this moment for calculating remainders
|
||||
remainder = moment.duration(this);
|
||||
|
||||
// add a reference to this duration object to the settings for use
|
||||
// in a template function
|
||||
settings.duration = this;
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
|
||||
// types
|
||||
types = settings.types = (isArray(settings.types) ? settings.types : settings.types.split(" "));
|
||||
|
||||
// template
|
||||
if (typeof settings.template === "function") {
|
||||
settings.template = settings.template.apply(settings);
|
||||
}
|
||||
|
||||
// tokenizer regexp
|
||||
tokenizer = new RegExp(map(types, function (type) {
|
||||
return settings[type].source;
|
||||
}).join("|"), "g");
|
||||
|
||||
// token type map function
|
||||
typeMap = function (token) {
|
||||
return find(types, function (type) {
|
||||
return settings[type].test(token);
|
||||
});
|
||||
};
|
||||
|
||||
// tokens array
|
||||
tokens = map(settings.template.match(tokenizer), function (token, index) {
|
||||
var type = typeMap(token),
|
||||
length = token.length;
|
||||
|
||||
return {
|
||||
index: index,
|
||||
length: length,
|
||||
|
||||
// replace escaped tokens with the non-escaped token text
|
||||
token: (type === "escape" ? token.replace(settings.escape, "$1") : token),
|
||||
|
||||
// ignore type on non-moment tokens
|
||||
type: ((type === "escape" || type === "general") ? null : type)
|
||||
|
||||
// calculate base value for all moment tokens
|
||||
//baseValue: ((type === "escape" || type === "general") ? null : this.as(type))
|
||||
};
|
||||
}, this);
|
||||
|
||||
// unique moment token types in the template (in order of descending magnitude)
|
||||
momentTypes = intersection(types, unique(compact(pluck(tokens, "type"))));
|
||||
|
||||
// exit early if there are no momentTypes
|
||||
if (!momentTypes.length) {
|
||||
return pluck(tokens, "token").join("");
|
||||
}
|
||||
|
||||
// calculate values for each token type in the template
|
||||
each(momentTypes, function (momentType, index) {
|
||||
var value, wholeValue, decimalValue, isLeast, isMost;
|
||||
|
||||
// calculate integer and decimal value portions
|
||||
value = remainder.as(momentType);
|
||||
wholeValue = (value > 0 ? Math.floor(value) : Math.ceil(value));
|
||||
decimalValue = value - wholeValue;
|
||||
|
||||
// is this the least-significant moment token found?
|
||||
isLeast = ((index + 1) === momentTypes.length);
|
||||
|
||||
// is this the most-significant moment token found?
|
||||
isMost = (!index);
|
||||
|
||||
// update tokens array
|
||||
// using this algorithm to not assume anything about
|
||||
// the order or frequency of any tokens
|
||||
each(tokens, function (token) {
|
||||
if (token.type === momentType) {
|
||||
extend(token, {
|
||||
value: value,
|
||||
wholeValue: wholeValue,
|
||||
decimalValue: decimalValue,
|
||||
isLeast: isLeast,
|
||||
isMost: isMost
|
||||
});
|
||||
|
||||
if (isMost) {
|
||||
// note the length of the most-significant moment token:
|
||||
// if it is greater than one and forceLength is not set, default forceLength to `true`
|
||||
if (settings.forceLength == null && token.length > 1) {
|
||||
settings.forceLength = 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"
|
||||
// shouldn't pad the `minutes` token even though it has length of two
|
||||
// if the template is "hh:mm:ss", the user clearly wanted everything padded so we should output "05:00"
|
||||
// if the user wanted the full padded output, they can set `{ trim: false }` to get "00:05:00"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// update remainder
|
||||
remainder.subtract(wholeValue, momentType);
|
||||
});
|
||||
|
||||
// trim tokens array
|
||||
if (settings.trim) {
|
||||
tokens = (settings.trim === "left" ? rest : initial)(tokens, function (token) {
|
||||
// return `true` if:
|
||||
// the token is not the least moment token (don't trim the least moment token)
|
||||
// the token is a moment token that does not have a value (don't trim moment tokens that have a whole value)
|
||||
return !(token.isLeast || (token.type != null && token.wholeValue));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// build output
|
||||
|
||||
// the first moment token can have special handling
|
||||
foundFirst = false;
|
||||
|
||||
// run the map in reverse order if trimming from the right
|
||||
if (settings.trim === "right") {
|
||||
tokens.reverse();
|
||||
}
|
||||
|
||||
tokens = map(tokens, function (token) {
|
||||
var val,
|
||||
decVal;
|
||||
|
||||
if (!token.type) {
|
||||
// if it is not a moment token, use the token as its own value
|
||||
return token.token;
|
||||
}
|
||||
|
||||
// apply negative precision formatting to the least-significant moment token
|
||||
if (token.isLeast && (settings.precision < 0)) {
|
||||
val = (Math.floor(token.wholeValue * Math.pow(10, settings.precision)) * Math.pow(10, -settings.precision)).toString();
|
||||
} else {
|
||||
val = token.wholeValue.toString();
|
||||
}
|
||||
|
||||
// remove negative sign from the beginning
|
||||
val = val.replace(/^\-/, "");
|
||||
|
||||
// apply token length formatting
|
||||
// special handling for the first moment token that is not the most significant in a trimmed template
|
||||
if (token.length > 1 && (foundFirst || token.isMost || settings.forceLength)) {
|
||||
val = padZero(val, token.length);
|
||||
}
|
||||
|
||||
// add decimal value if precision > 0
|
||||
if (token.isLeast && (settings.precision > 0)) {
|
||||
decVal = token.decimalValue.toString().replace(/^\-/, "").split(/\.|e\-/);
|
||||
switch (decVal.length) {
|
||||
case 1:
|
||||
val += "." + padZero(decVal[0], settings.precision, true).slice(0, settings.precision);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
val += "." + padZero(decVal[1], settings.precision, true).slice(0, settings.precision);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
val += "." + padZero(repeatZero((+decVal[2]) - 1) + (decVal[0] || "0") + decVal[1], settings.precision, true).slice(0, settings.precision);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "Moment Duration Format: unable to parse token decimal value.";
|
||||
}
|
||||
}
|
||||
|
||||
// add a negative sign if the value is negative and token is most significant
|
||||
if (token.isMost && token.value < 0) {
|
||||
val = "-" + val;
|
||||
}
|
||||
|
||||
foundFirst = true;
|
||||
|
||||
return val;
|
||||
});
|
||||
|
||||
// undo the reverse if trimming from the right
|
||||
if (settings.trim === "right") {
|
||||
tokens.reverse();
|
||||
}
|
||||
|
||||
return tokens.join("");
|
||||
};
|
||||
|
||||
moment.duration.fn.format.defaults = {
|
||||
// token definitions
|
||||
escape: /\[(.+?)\]/,
|
||||
years: /[Yy]+/,
|
||||
months: /M+/,
|
||||
weeks: /[Ww]+/,
|
||||
days: /[Dd]+/,
|
||||
hours: /[Hh]+/,
|
||||
minutes: /m+/,
|
||||
seconds: /s+/,
|
||||
milliseconds: /S+/,
|
||||
general: /.+?/,
|
||||
|
||||
// token type names
|
||||
// in order of descending magnitude
|
||||
// can be a space-separated token name list or an array of token names
|
||||
types: "escape years months weeks days hours minutes seconds milliseconds general",
|
||||
|
||||
// format options
|
||||
|
||||
// trim
|
||||
// "left" - template tokens are trimmed from the left until the first moment token that has a value >= 1
|
||||
// "right" - template tokens are trimmed from the right until the first moment token that has a value >= 1
|
||||
// (the final moment token is not trimmed, regardless of value)
|
||||
// `false` - template tokens are not trimmed
|
||||
trim: "left",
|
||||
|
||||
// precision
|
||||
// number of decimal digits to include after (to the right of) the decimal point (positive integer)
|
||||
// or the number of digits to truncate to 0 before (to the left of) the decimal point (negative integer)
|
||||
precision: 0,
|
||||
|
||||
// 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,
|
||||
|
||||
// template used to format 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
|
||||
template: function () {
|
||||
var types = this.types,
|
||||
dur = this.duration,
|
||||
lastType = findLast(types, function (type) {
|
||||
return dur._data[type];
|
||||
});
|
||||
|
||||
// default template strings for each duration dimension type
|
||||
switch (lastType) {
|
||||
case "seconds":
|
||||
return "h:mm:ss";
|
||||
case "minutes":
|
||||
return "d[d] h:mm";
|
||||
case "hours":
|
||||
return "d[d] h[h]";
|
||||
case "days":
|
||||
return "M[m] d[d]";
|
||||
case "weeks":
|
||||
return "y[y] w[w]";
|
||||
case "months":
|
||||
return "y[y] M[m]";
|
||||
case "years":
|
||||
return "y[y]";
|
||||
default:
|
||||
return "y[y] M[m] d[d] h:mm:ss";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})(this);
|
Reference in New Issue
Block a user