482 lines
No EOL
16 KiB
JavaScript
Executable file
482 lines
No EOL
16 KiB
JavaScript
Executable file
|
|
(function() {
|
|
|
|
// Baseline setup
|
|
// --------------
|
|
|
|
// Establish the root object, `window` in the browser, or `global` on the server.
|
|
var root = this;
|
|
|
|
// Save the previous value of the `humanize` variable.
|
|
var previousHumanize = root.humanize;
|
|
|
|
var humanize = {};
|
|
|
|
if (typeof exports !== 'undefined') {
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
exports = module.exports = humanize;
|
|
}
|
|
exports.humanize = humanize;
|
|
} else {
|
|
if (typeof define === 'function' && define.amd) {
|
|
define('humanize', function() {
|
|
return humanize;
|
|
});
|
|
}
|
|
root.humanize = humanize;
|
|
}
|
|
|
|
humanize.noConflict = function() {
|
|
root.humanize = previousHumanize;
|
|
return this;
|
|
};
|
|
|
|
humanize.pad = function(str, count, padChar, type) {
|
|
str += '';
|
|
if (!padChar) {
|
|
padChar = ' ';
|
|
} else if (padChar.length > 1) {
|
|
padChar = padChar.charAt(0);
|
|
}
|
|
type = (type === undefined) ? 'left' : 'right';
|
|
|
|
if (type === 'right') {
|
|
while (str.length < count) {
|
|
str = str + padChar;
|
|
}
|
|
} else {
|
|
// default to left
|
|
while (str.length < count) {
|
|
str = padChar + str;
|
|
}
|
|
}
|
|
|
|
return str;
|
|
};
|
|
|
|
// gets current unix time
|
|
humanize.time = function() {
|
|
return new Date().getTime() / 1000;
|
|
};
|
|
|
|
/**
|
|
* PHP-inspired date
|
|
*/
|
|
|
|
/* jan feb mar apr may jun jul aug sep oct nov dec */
|
|
var dayTableCommon = [ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ];
|
|
var dayTableLeap = [ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 ];
|
|
// var mtable_common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
// static int ml_table_leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
|
|
|
|
humanize.date = function(format, timestamp) {
|
|
var jsdate = ((timestamp === undefined) ? new Date() : // Not provided
|
|
(timestamp instanceof Date) ? new Date(timestamp) : // JS Date()
|
|
new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
|
|
);
|
|
|
|
var formatChr = /\\?([a-z])/gi;
|
|
var formatChrCb = function (t, s) {
|
|
return f[t] ? f[t]() : s;
|
|
};
|
|
|
|
var shortDayTxt = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
var monthTxt = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
|
|
var f = {
|
|
/* Day */
|
|
// Day of month w/leading 0; 01..31
|
|
d: function () { return humanize.pad(f.j(), 2, '0'); },
|
|
|
|
// Shorthand day name; Mon..Sun
|
|
D: function () { return f.l().slice(0, 3); },
|
|
|
|
// Day of month; 1..31
|
|
j: function () { return jsdate.getDate(); },
|
|
|
|
// Full day name; Monday..Sunday
|
|
l: function () { return shortDayTxt[f.w()]; },
|
|
|
|
// ISO-8601 day of week; 1[Mon]..7[Sun]
|
|
N: function () { return f.w() || 7; },
|
|
|
|
// Ordinal suffix for day of month; st, nd, rd, th
|
|
S: function () {
|
|
var j = f.j();
|
|
return j > 4 && j < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[j % 10] || 'th';
|
|
},
|
|
|
|
// Day of week; 0[Sun]..6[Sat]
|
|
w: function () { return jsdate.getDay(); },
|
|
|
|
// Day of year; 0..365
|
|
z: function () {
|
|
return (f.L() ? dayTableLeap[f.n()] : dayTableCommon[f.n()]) + f.j() - 1;
|
|
},
|
|
|
|
/* Week */
|
|
// ISO-8601 week number
|
|
W: function () {
|
|
// days between midweek of this week and jan 4
|
|
// (f.z() - f.N() + 1 + 3.5) - 3
|
|
var midWeekDaysFromJan4 = f.z() - f.N() + 1.5;
|
|
// 1 + number of weeks + rounded week
|
|
return humanize.pad(1 + Math.floor(Math.abs(midWeekDaysFromJan4) / 7) + (midWeekDaysFromJan4 % 7 > 3.5 ? 1 : 0), 2, '0');
|
|
},
|
|
|
|
/* Month */
|
|
// Full month name; January..December
|
|
F: function () { return monthTxt[jsdate.getMonth()]; },
|
|
|
|
// Month w/leading 0; 01..12
|
|
m: function () { return humanize.pad(f.n(), 2, '0'); },
|
|
|
|
// Shorthand month name; Jan..Dec
|
|
M: function () { return f.F().slice(0, 3); },
|
|
|
|
// Month; 1..12
|
|
n: function () { return jsdate.getMonth() + 1; },
|
|
|
|
// Days in month; 28..31
|
|
t: function () { return (new Date(f.Y(), f.n(), 0)).getDate(); },
|
|
|
|
/* Year */
|
|
// Is leap year?; 0 or 1
|
|
L: function () { return new Date(f.Y(), 1, 29).getMonth() === 1 ? 1 : 0; },
|
|
|
|
// ISO-8601 year
|
|
o: function () {
|
|
var n = f.n();
|
|
var W = f.W();
|
|
return f.Y() + (n === 12 && W < 9 ? -1 : n === 1 && W > 9);
|
|
},
|
|
|
|
// Full year; e.g. 1980..2010
|
|
Y: function () { return jsdate.getFullYear(); },
|
|
|
|
// Last two digits of year; 00..99
|
|
y: function () { return (String(f.Y())).slice(-2); },
|
|
|
|
/* Time */
|
|
// am or pm
|
|
a: function () { return jsdate.getHours() > 11 ? 'pm' : 'am'; },
|
|
|
|
// AM or PM
|
|
A: function () { return f.a().toUpperCase(); },
|
|
|
|
// Swatch Internet time; 000..999
|
|
B: function () {
|
|
var unixTime = jsdate.getTime() / 1000;
|
|
var secondsPassedToday = unixTime % 86400 + 3600; // since it's based off of UTC+1
|
|
if (secondsPassedToday < 0) { secondsPassedToday += 86400; }
|
|
var beats = ((secondsPassedToday) / 86.4) % 1000;
|
|
if (unixTime < 0) {
|
|
return Math.ceil(beats);
|
|
}
|
|
return Math.floor(beats);
|
|
},
|
|
|
|
// 12-Hours; 1..12
|
|
g: function () { return f.G() % 12 || 12; },
|
|
|
|
// 24-Hours; 0..23
|
|
G: function () { return jsdate.getHours(); },
|
|
|
|
// 12-Hours w/leading 0; 01..12
|
|
h: function () { return humanize.pad(f.g(), 2, '0'); },
|
|
|
|
// 24-Hours w/leading 0; 00..23
|
|
H: function () { return humanize.pad(f.G(), 2, '0'); },
|
|
|
|
// Minutes w/leading 0; 00..59
|
|
i: function () { return humanize.pad(jsdate.getMinutes(), 2, '0'); },
|
|
|
|
// Seconds w/leading 0; 00..59
|
|
s: function () { return humanize.pad(jsdate.getSeconds(), 2, '0'); },
|
|
|
|
// Microseconds; 000000-999000
|
|
u: function () { return humanize.pad(jsdate.getMilliseconds() * 1000, 6, '0'); },
|
|
|
|
// Whether or not the date is in daylight savings time
|
|
/*
|
|
I: function () {
|
|
// Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC.
|
|
// If they are not equal, then DST is observed.
|
|
var Y = f.Y();
|
|
return 0 + ((new Date(Y, 0) - Date.UTC(Y, 0)) !== (new Date(Y, 6) - Date.UTC(Y, 6)));
|
|
},
|
|
*/
|
|
|
|
// Difference to GMT in hour format; e.g. +0200
|
|
O: function () {
|
|
var tzo = jsdate.getTimezoneOffset();
|
|
var tzoNum = Math.abs(tzo);
|
|
return (tzo > 0 ? '-' : '+') + humanize.pad(Math.floor(tzoNum / 60) * 100 + tzoNum % 60, 4, '0');
|
|
},
|
|
|
|
// Difference to GMT w/colon; e.g. +02:00
|
|
P: function () {
|
|
var O = f.O();
|
|
return (O.substr(0, 3) + ':' + O.substr(3, 2));
|
|
},
|
|
|
|
// Timezone offset in seconds (-43200..50400)
|
|
Z: function () { return -jsdate.getTimezoneOffset() * 60; },
|
|
|
|
// Full Date/Time, ISO-8601 date
|
|
c: function () { return 'Y-m-d\\TH:i:sP'.replace(formatChr, formatChrCb); },
|
|
|
|
// RFC 2822
|
|
r: function () { return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb); },
|
|
|
|
// Seconds since UNIX epoch
|
|
U: function () { return jsdate.getTime() / 1000 || 0; }
|
|
};
|
|
|
|
return format.replace(formatChr, formatChrCb);
|
|
};
|
|
|
|
|
|
/**
|
|
* format number by adding thousands separaters and significant digits while rounding
|
|
*/
|
|
humanize.numberFormat = function(number, decimals, decPoint, thousandsSep) {
|
|
decimals = isNaN(decimals) ? 2 : Math.abs(decimals);
|
|
decPoint = (decPoint === undefined) ? '.' : decPoint;
|
|
thousandsSep = (thousandsSep === undefined) ? ',' : thousandsSep;
|
|
|
|
var sign = number < 0 ? '-' : '';
|
|
number = Math.abs(+number || 0);
|
|
|
|
var intPart = parseInt(number.toFixed(decimals), 10) + '';
|
|
var j = intPart.length > 3 ? intPart.length % 3 : 0;
|
|
|
|
return sign + (j ? intPart.substr(0, j) + thousandsSep : '') + intPart.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep) + (decimals ? decPoint + Math.abs(number - intPart).toFixed(decimals).slice(2) : '');
|
|
};
|
|
|
|
|
|
/**
|
|
* For dates that are the current day or within one day, return 'today', 'tomorrow' or 'yesterday', as appropriate.
|
|
* Otherwise, format the date using the passed in format string.
|
|
*
|
|
* Examples (when 'today' is 17 Feb 2007):
|
|
* 16 Feb 2007 becomes yesterday.
|
|
* 17 Feb 2007 becomes today.
|
|
* 18 Feb 2007 becomes tomorrow.
|
|
* Any other day is formatted according to given argument or the DATE_FORMAT setting if no argument is given.
|
|
*/
|
|
humanize.naturalDay = function(timestamp, format) {
|
|
timestamp = (timestamp === undefined) ? humanize.time() : timestamp;
|
|
format = (format === undefined) ? 'Y-m-d' : format;
|
|
|
|
var oneDay = 86400;
|
|
var d = new Date();
|
|
var today = (new Date(d.getFullYear(), d.getMonth(), d.getDate())).getTime() / 1000;
|
|
|
|
if (timestamp < today && timestamp >= today - oneDay) {
|
|
return 'yesterday';
|
|
} else if (timestamp >= today && timestamp < today + oneDay) {
|
|
return 'today';
|
|
} else if (timestamp >= today + oneDay && timestamp < today + 2 * oneDay) {
|
|
return 'tomorrow';
|
|
}
|
|
|
|
return humanize.date(format, timestamp);
|
|
};
|
|
|
|
/**
|
|
* returns a string representing how many seconds, minutes or hours ago it was or will be in the future
|
|
* Will always return a relative time, most granular of seconds to least granular of years. See unit tests for more details
|
|
*/
|
|
humanize.relativeTime = function(timestamp) {
|
|
timestamp = (timestamp === undefined) ? humanize.time() : timestamp;
|
|
|
|
var currTime = humanize.time();
|
|
var timeDiff = currTime - timestamp;
|
|
|
|
// within 2 seconds
|
|
if (timeDiff < 2 && timeDiff > -2) {
|
|
return (timeDiff >= 0 ? 'just ' : '') + 'now';
|
|
}
|
|
|
|
// within a minute
|
|
if (timeDiff < 60 && timeDiff > -60) {
|
|
return (timeDiff >= 0 ? Math.floor(timeDiff) + ' seconds ago' : 'in ' + Math.floor(-timeDiff) + ' seconds');
|
|
}
|
|
|
|
// within 2 minutes
|
|
if (timeDiff < 120 && timeDiff > -120) {
|
|
return (timeDiff >= 0 ? 'about a minute ago' : 'in about a minute');
|
|
}
|
|
|
|
// within an hour
|
|
if (timeDiff < 3600 && timeDiff > -3600) {
|
|
return (timeDiff >= 0 ? Math.floor(timeDiff / 60) + ' minutes ago' : 'in ' + Math.floor(-timeDiff / 60) + ' minutes');
|
|
}
|
|
|
|
// within 2 hours
|
|
if (timeDiff < 7200 && timeDiff > -7200) {
|
|
return (timeDiff >= 0 ? 'about an hour ago' : 'in about an hour');
|
|
}
|
|
|
|
// within 24 hours
|
|
if (timeDiff < 86400 && timeDiff > -86400) {
|
|
return (timeDiff >= 0 ? Math.floor(timeDiff / 3600) + ' hours ago' : 'in ' + Math.floor(-timeDiff / 3600) + ' hours');
|
|
}
|
|
|
|
// within 2 days
|
|
var days2 = 2 * 86400;
|
|
if (timeDiff < days2 && timeDiff > -days2) {
|
|
return (timeDiff >= 0 ? '1 day ago' : 'in 1 day');
|
|
}
|
|
|
|
// within 29 days
|
|
var days29 = 29 * 86400;
|
|
if (timeDiff < days29 && timeDiff > -days29) {
|
|
return (timeDiff >= 0 ? Math.floor(timeDiff / 86400) + ' days ago' : 'in ' + Math.floor(-timeDiff / 86400) + ' days');
|
|
}
|
|
|
|
// within 60 days
|
|
var days60 = 60 * 86400;
|
|
if (timeDiff < days60 && timeDiff > -days60) {
|
|
return (timeDiff >= 0 ? 'about a month ago' : 'in about a month');
|
|
}
|
|
|
|
var currTimeYears = parseInt(humanize.date('Y', currTime), 10);
|
|
var timestampYears = parseInt(humanize.date('Y', timestamp), 10);
|
|
var currTimeMonths = currTimeYears * 12 + parseInt(humanize.date('n', currTime), 10);
|
|
var timestampMonths = timestampYears * 12 + parseInt(humanize.date('n', timestamp), 10);
|
|
|
|
// within a year
|
|
var monthDiff = currTimeMonths - timestampMonths;
|
|
if (monthDiff < 12 && monthDiff > -12) {
|
|
return (monthDiff >= 0 ? monthDiff + ' months ago' : 'in ' + (-monthDiff) + ' months');
|
|
}
|
|
|
|
var yearDiff = currTimeYears - timestampYears;
|
|
if (yearDiff < 2 && yearDiff > -2) {
|
|
return (yearDiff >= 0 ? 'a year ago' : 'in a year');
|
|
}
|
|
|
|
return (yearDiff >= 0 ? yearDiff + ' years ago' : 'in ' + (-yearDiff) + ' years');
|
|
};
|
|
|
|
/**
|
|
* Converts an integer to its ordinal as a string.
|
|
*
|
|
* 1 becomes 1st
|
|
* 2 becomes 2nd
|
|
* 3 becomes 3rd etc
|
|
*/
|
|
humanize.ordinal = function(number) {
|
|
number = parseInt(number, 10);
|
|
number = isNaN(number) ? 0 : number;
|
|
var sign = number < 0 ? '-' : '';
|
|
number = Math.abs(number);
|
|
var tens = number % 100;
|
|
|
|
return sign + number + (tens > 4 && tens < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[number % 10] || 'th');
|
|
};
|
|
|
|
/**
|
|
* Formats the value like a 'human-readable' file size (i.e. '13 KB', '4.1 MB', '102 bytes', etc).
|
|
*
|
|
* For example:
|
|
* If value is 123456789, the output would be 117.7 MB.
|
|
*/
|
|
humanize.filesize = function(filesize, kilo, decimals, decPoint, thousandsSep, suffixSep) {
|
|
kilo = (kilo === undefined) ? 1024 : kilo;
|
|
if (filesize <= 0) { return '0 bytes'; }
|
|
if (filesize < kilo && decimals === undefined) { decimals = 0; }
|
|
if (suffixSep === undefined) { suffixSep = ' '; }
|
|
return humanize.intword(filesize, ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'], kilo, decimals, decPoint, thousandsSep, suffixSep);
|
|
};
|
|
|
|
/**
|
|
* Formats the value like a 'human-readable' number (i.e. '13 K', '4.1 M', '102', etc).
|
|
*
|
|
* For example:
|
|
* If value is 123456789, the output would be 117.7 M.
|
|
*/
|
|
humanize.intword = function(number, units, kilo, decimals, decPoint, thousandsSep, suffixSep) {
|
|
var humanized, unit;
|
|
|
|
units = units || ['', 'K', 'M', 'B', 'T'],
|
|
unit = units.length - 1,
|
|
kilo = kilo || 1000,
|
|
decimals = isNaN(decimals) ? 2 : Math.abs(decimals),
|
|
decPoint = decPoint || '.',
|
|
thousandsSep = thousandsSep || ',',
|
|
suffixSep = suffixSep || '';
|
|
|
|
for (var i=0; i < units.length; i++) {
|
|
if (number < Math.pow(kilo, i+1)) {
|
|
unit = i;
|
|
break;
|
|
}
|
|
}
|
|
humanized = number / Math.pow(kilo, unit);
|
|
|
|
var suffix = units[unit] ? suffixSep + units[unit] : '';
|
|
return humanize.numberFormat(humanized, decimals, decPoint, thousandsSep) + suffix;
|
|
};
|
|
|
|
/**
|
|
* Replaces line breaks in plain text with appropriate HTML
|
|
* A single newline becomes an HTML line break (<br />) and a new line followed by a blank line becomes a paragraph break (</p>).
|
|
*
|
|
* For example:
|
|
* If value is Joel\nis a\n\nslug, the output will be <p>Joel<br />is a</p><p>slug</p>
|
|
*/
|
|
humanize.linebreaks = function(str) {
|
|
// remove beginning and ending newlines
|
|
str = str.replace(/^([\n|\r]*)/, '');
|
|
str = str.replace(/([\n|\r]*)$/, '');
|
|
|
|
// normalize all to \n
|
|
str = str.replace(/(\r\n|\n|\r)/g, "\n");
|
|
|
|
// any consecutive new lines more than 2 gets turned into p tags
|
|
str = str.replace(/(\n{2,})/g, '</p><p>');
|
|
|
|
// any that are singletons get turned into br
|
|
str = str.replace(/\n/g, '<br />');
|
|
return '<p>' + str + '</p>';
|
|
};
|
|
|
|
/**
|
|
* Converts all newlines in a piece of plain text to HTML line breaks (<br />).
|
|
*/
|
|
humanize.nl2br = function(str) {
|
|
return str.replace(/(\r\n|\n|\r)/g, '<br />');
|
|
};
|
|
|
|
/**
|
|
* Truncates a string if it is longer than the specified number of characters.
|
|
* Truncated strings will end with a translatable ellipsis sequence ('…').
|
|
*/
|
|
humanize.truncatechars = function(string, length) {
|
|
if (string.length <= length) { return string; }
|
|
return string.substr(0, length) + '…';
|
|
};
|
|
|
|
/**
|
|
* Truncates a string after a certain number of words.
|
|
* Newlines within the string will be removed.
|
|
*/
|
|
humanize.truncatewords = function(string, numWords) {
|
|
var words = string.split(' ');
|
|
if (words.length < numWords) { return string; }
|
|
return words.slice(0, numWords).join(' ') + '…';
|
|
};
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
//////////////////
|
|
// WEBPACK FOOTER
|
|
// ./~/humanize/humanize.js
|
|
// module id = 475
|
|
// module chunks = 4
|