Code:
Ext.fc.fuzzyDate = function() {
var defaultConfig = function() {
return{
refreshInterval: 60,
onErrorWriteTitle: true,
itemSelector: 'span.fuzzyDate',
cutoff: 172800,
defaultReturnFormat: 'd/m/Y, H:i',
dateFormats: [
"Y-m-d H:i:s", //ISO8601Long
"Y-m-d", //ISO8601Short
"h:i:s", //time
"H:i:s", //time
"n/j/Y", //ShortDate
"l, F d, Y", //LongDate
"l, F d, Y g:i:s A", //FullDateTime
"F d", //MonthDay
"g:i A", //ShortTime
"g:i:s A", //LongTime
"Y-m-d\\TH:i:s", //SortableDateTime
"Y-m-d H:i:sO", //UniversalSortableDateTime
"F, Y", //YearMonth
"d/m/Y, H:i:s", // Euro format
"D, d F Y G:i:s O" // Twitter format
],
translation: {
prefixAgo : '',
prefixFromNow : '',
suffixAgo : "ago",
suffixFromNow : "from now",
now : "seconds",
seconds : "less than a minute",
minute : "about a minute",
minutes : "%d minutes",
hour : "about an hour",
hours : "about %d hours",
day : "a day",
days : "about %d days",
month : "about a month",
months : "about %d months",
year : "about a year",
years : "about %d years"
},
offsets: {
//values are exclusive, they will be evaluated as date < now or date < oneYear
now : 15, //number of seconds a date is considered seconds
minute : 45, //number of seconds a date is considered less than a minute
minuteOffset: 90, //number of seconds a date is considered about a minute
xminutes : 50, //number of minutes a date should be represented as x minutes
oneHour : 80, //number of minutes a date should be represented as one hour
xHours : 24, //number of hours a date should be represented as x hours
oneDay : 48, //number of hours a date should be represented as one day
xDays : 30, //number of days a date should be represented as X days
oneMonth : 60, //number of days a date should be represented as one month
xMonths : 365, //number of days a date should be represented as x months
oneYear : 2 //number of years a date should be represented as one year
}
}
};
/**
* Adds the number of minutes or seconds or days, etc.
* @param text
* @param value
*/
function sprintf(text, value) {
//I just need %d for one parameter
return text.replace(/%d/, value);
}
/**
* Determines which format to use
* @param str
* @param formats
*/
function parseDate(str, formats) {
var d = null;
for (i = 0; i < formats.length; i++) {
d = Date.parseDate(str, formats[i]);
if (d) {
return d
}
}
return false;
}
/**
* Returns the relative time
* @param dateObject
* @param options
*/
var dateTimeToString = function (dateObject, options) {
var t = options.translation,
cutoff = options.cutoff,
defaultReturnFormat = options.defaultReturnFormat,
now = new Date(),
offset = now.format('U') - dateObject.format('U');
//if < 0 then date is in future
if (Math.abs(offset) < cutoff) {
if (offset < 0) {
suffix = t.suffixFromNow;
prefix = t.prefixFromNow;
} else {
suffix = t.suffixAgo;
prefix = t.prefixAgo;
}
var seconds = Math.abs(offset);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
var days = Math.floor(hours / 24);
var years = Math.floor(days / 365);
var fuzzy = false ||
seconds < options.offsets.now && sprintf(t.seconds, Math.round(now)) || //seconds
seconds < options.offsets.minute && sprintf(t.seconds, Math.round(seconds)) || //about 1 minute
seconds < options.offsets.minuteOffset && sprintf(t.minute, 1) || //about x minutes
minutes < options.offsets.xminutes && sprintf(t.minutes, Math.round(minutes)) || //about 1 hour
minutes < options.offsets.oneHour && sprintf(t.hour, 1) || //about x hours
hours < options.offsets.xHours && sprintf(t.hours, Math.round(hours)) || //about 1 day
hours < options.offsets.oneDay && sprintf(t.day, 1) || //about x days
days < options.offsets.xDays && sprintf(t.days, Math.floor(days)) || //about 1 month
days < options.offsets.oneMonth && sprintf(t.month, 1) || //about x months
days < options.offsets.xMonths && sprintf(t.months, Math.floor(days / 30)) || //about 1 year
years < options.offsets.oneYear && sprintf(t.year, 1) || //about x years
sprintf(t.years, Math.floor(years));
return prefix + " " + fuzzy + " " + suffix;
} else {
return dateObject.format(defaultReturnFormat);
}
};
/**
* Parses the custom options
* @param config
*/
var processOptions = function(config) {
var o = defaultConfig();
var options = {};
Ext.apply(options, config, o);
return options;
};
//public start
return{
options: null,
items: [],
/**
* Constructor
* @param config
*/
init : function (config) {
this.options = processOptions(config);
this.refresh();
},
/**
* Returns the translated date
* @param str
* @param options
*/
translate : function(str, options) {
var d = parseDate(str, options.dateFormats);
if (d) {
return (dateTimeToString(d, options));
} else {
if (options.onErrorWriteTitle) {
return (str);
}
}
return false;
},
/**
* Refreshes the relative time of all the Components matching the itemSelector
*/
refresh: function() {
Ext.select(this.options.itemSelector).each(function(el, c, idx) {
el.update(this.translate(el.dom.title, this.options));
}, this);
if (this.options.refreshInterval > 0) {
Ext.defer(this.refresh, this.options.refreshInterval * 1000, this);
}
},
/**
* Translates the date contained in a specific Component, identified by its id
* @param domId
* @param config
*/
applyTo: function (domId, config) {
var options = processOptions(config),
el = Ext.get(domId);
el.update(this.translate(el.dom.title, options));
if (options.refreshInterval > 0) {
Ext.defer(this.applyTo, options.refreshInterval * 1000, this, [domId, config]);
}
}
};//public -- end
};