mirror of
https://github.com/scratchfoundation/jquery-timeago.git
synced 2025-02-17 08:30:52 -05:00
This is handy for working with RequireJS setups that use jQuery in noConflict mode. Without it this plugin continually tries to access the global object.
162 lines
4.9 KiB
JavaScript
162 lines
4.9 KiB
JavaScript
/**
|
|
* Timeago is a jQuery plugin that makes it easy to support automatically
|
|
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
|
*
|
|
* @name timeago
|
|
* @version 0.11.4
|
|
* @requires jQuery v1.2.3+
|
|
* @author Ryan McGeary
|
|
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
|
*
|
|
* For usage and examples, visit:
|
|
* http://timeago.yarp.com/
|
|
*
|
|
* Copyright (c) 2008-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
|
|
*/
|
|
|
|
(function(factory) {
|
|
// Add jQuery via AMD registration or browser globals
|
|
if (typeof define === 'function' && define.amd) {
|
|
define([ 'jquery' ], factory);
|
|
}
|
|
else {
|
|
factory(jQuery);
|
|
}
|
|
}(function($) {
|
|
$.timeago = function(timestamp) {
|
|
if (timestamp instanceof Date) {
|
|
return inWords(timestamp);
|
|
} else if (typeof timestamp === "string") {
|
|
return inWords($.timeago.parse(timestamp));
|
|
} else if (typeof timestamp === "number") {
|
|
return inWords(new Date(timestamp));
|
|
} else {
|
|
return inWords($.timeago.datetime(timestamp));
|
|
}
|
|
};
|
|
var $t = $.timeago;
|
|
|
|
$.extend($.timeago, {
|
|
settings: {
|
|
refreshMillis: 60000,
|
|
allowFuture: false,
|
|
strings: {
|
|
prefixAgo: null,
|
|
prefixFromNow: null,
|
|
suffixAgo: "ago",
|
|
suffixFromNow: "from now",
|
|
seconds: "less than a minute",
|
|
minute: "about a minute",
|
|
minutes: "%d minutes",
|
|
hour: "about an hour",
|
|
hours: "about %d hours",
|
|
day: "a day",
|
|
days: "%d days",
|
|
month: "about a month",
|
|
months: "%d months",
|
|
year: "about a year",
|
|
years: "%d years",
|
|
wordSeparator: " ",
|
|
numbers: []
|
|
}
|
|
},
|
|
inWords: function(distanceMillis) {
|
|
var $l = this.settings.strings;
|
|
var prefix = $l.prefixAgo;
|
|
var suffix = $l.suffixAgo;
|
|
if (this.settings.allowFuture) {
|
|
if (distanceMillis < 0) {
|
|
prefix = $l.prefixFromNow;
|
|
suffix = $l.suffixFromNow;
|
|
}
|
|
}
|
|
|
|
var seconds = Math.abs(distanceMillis) / 1000;
|
|
var minutes = seconds / 60;
|
|
var hours = minutes / 60;
|
|
var days = hours / 24;
|
|
var years = days / 365;
|
|
|
|
function substitute(stringOrFunction, number) {
|
|
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
|
|
var value = ($l.numbers && $l.numbers[number]) || number;
|
|
return string.replace(/%d/i, value);
|
|
}
|
|
|
|
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
|
|
seconds < 90 && substitute($l.minute, 1) ||
|
|
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
|
|
minutes < 90 && substitute($l.hour, 1) ||
|
|
hours < 24 && substitute($l.hours, Math.round(hours)) ||
|
|
hours < 42 && substitute($l.day, 1) ||
|
|
days < 30 && substitute($l.days, Math.round(days)) ||
|
|
days < 45 && substitute($l.month, 1) ||
|
|
days < 365 && substitute($l.months, Math.round(days / 30)) ||
|
|
years < 1.5 && substitute($l.year, 1) ||
|
|
substitute($l.years, Math.round(years));
|
|
|
|
var separator = $l.wordSeparator || "";
|
|
if ($l.wordSeparator === undefined) { separator = " "; }
|
|
return $.trim([prefix, words, suffix].join(separator));
|
|
},
|
|
parse: function(iso8601) {
|
|
var s = $.trim(iso8601);
|
|
s = s.replace(/\.\d+/,""); // remove milliseconds
|
|
s = s.replace(/-/,"/").replace(/-/,"/");
|
|
s = s.replace(/T/," ").replace(/Z/," UTC");
|
|
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
|
return new Date(s);
|
|
},
|
|
datetime: function(elem) {
|
|
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
|
|
return $t.parse(iso8601);
|
|
},
|
|
isTime: function(elem) {
|
|
// jQuery's `is()` doesn't play well with HTML5 in IE
|
|
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
|
|
}
|
|
});
|
|
|
|
$.fn.timeago = function() {
|
|
var self = this;
|
|
self.each(refresh);
|
|
|
|
var $s = $t.settings;
|
|
if ($s.refreshMillis > 0) {
|
|
setInterval(function() { self.each(refresh); }, $s.refreshMillis);
|
|
}
|
|
return self;
|
|
};
|
|
|
|
function refresh() {
|
|
var data = prepareData(this);
|
|
if (!isNaN(data.datetime)) {
|
|
$(this).text(inWords(data.datetime));
|
|
}
|
|
return this;
|
|
}
|
|
|
|
function prepareData(element) {
|
|
element = $(element);
|
|
if (!element.data("timeago")) {
|
|
element.data("timeago", { datetime: $t.datetime(element) });
|
|
var text = $.trim(element.text());
|
|
if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
|
|
element.attr("title", text);
|
|
}
|
|
}
|
|
return element.data("timeago");
|
|
}
|
|
|
|
function inWords(date) {
|
|
return $t.inWords(distance(date));
|
|
}
|
|
|
|
function distance(date) {
|
|
return (new Date().getTime() - date.getTime());
|
|
}
|
|
|
|
// fix for IE6 suckage
|
|
document.createElement("abbr");
|
|
document.createElement("time");
|
|
}));
|