automatically updating times for posts on topic

moved moment.js into localization file (we need to localize it)
added helpers for date formatting use, moment().shortDate() moment().longDate() moment().shortDateNoYear()
This commit is contained in:
Sam 2013-06-11 17:25:50 +10:00
parent 6d85dc1724
commit c2cfbce9ce
8 changed files with 65 additions and 22 deletions

View file

@ -4,15 +4,10 @@ Discourse.Formatter = (function(){
relativeAgeMedium, relativeAgeMediumSpan, longDate, toTitleCase,
shortDate;
var shortDateNoYearFormat = Ember.String.i18n("dates.short_date_no_year");
var longDateFormat = Ember.String.i18n("dates.long_date");
var shortDateFormat = Ember.String.i18n("dates.short_date");
shortDate = function(date){
return moment(date).format(shortDateFormat);
return moment(date).shortDate();
};
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
// TODO: locale support ?
toTitleCase = function toTitleCase(str)
@ -23,14 +18,14 @@ Discourse.Formatter = (function(){
}
longDate = function(dt) {
return moment(dt).format(longDateFormat);
return moment(dt).longDate();
};
updateRelativeAge = function(elems) {
// jQuery .each
elems.each(function(){
var $this = $(this);
$this.html(relativeAge(new Date($this.data('time')), $this.data('format')));
$this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false}));
});
};
@ -38,7 +33,17 @@ Discourse.Formatter = (function(){
options = options || {};
var format = options.format || "tiny";
return "<span class='relative-date' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relativeAge(date, options) + "</span>";
var append = "";
if(format === 'medium') {
append = " date' title='" + longDate(date);
if(options.leaveAgo) {
format = 'medium-with-ago';
}
options.wrapInSpan = false;
}
return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relativeAge(date, options) + "</span>";
};
@ -139,7 +144,7 @@ Discourse.Formatter = (function(){
if ((new Date()).getFullYear() !== date.getFullYear()) {
displayDate = shortDate(date);
} else {
displayDate = moment(date).format(shortDateNoYearFormat);
displayDate = moment(date).shortDateNoYear();
}
} else {
displayDate = relativeAgeMediumSpan(distance, leaveAgo);
@ -160,6 +165,8 @@ Discourse.Formatter = (function(){
return relativeAgeTiny(date, options);
} else if (format === "medium") {
return relativeAgeMedium(date, options);
} else if (format === 'medium-with-ago') {
return relativeAgeMedium(date, _.extend(options, {format: 'medium', leaveAgo: true}));
}
return "UNKNOWN FORMAT";

View file

@ -212,7 +212,7 @@ Handlebars.registerHelper('unboundAge', function(property, options) {
Handlebars.registerHelper('editDate', function(property, options) {
// autoupdating this is going to be painful
var date = new Date(Ember.Handlebars.get(this, property, options));
return new Handlebars.SafeString(Discourse.Formatter.relativeAge(date, {format: 'medium', leaveAgo: true, wrapInSpan: false}));
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(date, {format: 'medium', leaveAgo: true, wrapInSpan: false}));
});
/**
@ -286,6 +286,6 @@ Handlebars.registerHelper('date', function(property, options) {
if (val) {
date = new Date(val);
}
return new Handlebars.SafeString(Discourse.Formatter.relativeAge(date, {format: 'medium', leaveAgo: leaveAgo}));
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(date, {format: 'medium', leaveAgo: leaveAgo}));
});

View file

@ -8,9 +8,6 @@
en:
js:
dates:
short_date_no_year: "D MMM"
short_date: "D MMM, YYYY"
long_date: "MMMM D, YYYY h:mma"
tiny:
half_a_minute: "< 1m"
less_than_x_seconds:

View file

@ -5,6 +5,10 @@
# http://yamllint.com/
en:
dates:
short_date_no_year: "D MMM"
short_date: "D MMM, YYYY"
long_date: "MMMM D, YYYY h:mma"
time:
formats:
short: "%m-%d-%Y"

View file

@ -18,11 +18,26 @@ module JsLocaleHelper
result = generate_message_format(message_formats, locale_str)
result << "I18n.translations = #{translations.to_json};\n"
result << "I18n.locale = '#{locale_str}'\n"
result << "I18n.locale = '#{locale_str}';\n"
# loading moment here cause we must customize it
result << File.read("#{Rails.root}/lib/javascripts/moment.js")
result << moment_locale(locale_str)
result << moment_formats
result
end
def self.moment_formats
result = ""
result << moment_format_function('short_date_no_year')
result << moment_format_function('short_date')
result << moment_format_function('long_date')
end
def self.moment_format_function(name)
format = I18n.t("dates." << name)
result = "moment.fn.#{name.camelize(:lower)} = function(){ return this.format('#{format}'); };\n"
end
def self.moment_locale(locale_str)
filename = Rails.root + "lib/javascript/moment_locale/#{locale_str}.js"
if File.exists?(filename)

View file

@ -85,12 +85,22 @@ describe("Discourse.Formatter", function() {
describe("autoUpdatingRelativeAge", function(){
it("can format dates", function(){
var d = new Date();
var d = moment().subtract('days',1).toDate();
var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d));
expect($elem.data('format')).toBe("tiny");
expect($elem.data('time')).toBe(d.getTime());
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d,{format: 'medium', leaveAgo: true}));
expect($elem.data('format')).toBe("medium-with-ago");
expect($elem.data('time')).toBe(d.getTime());
expect($elem.attr('title')).toBe(moment(d).longDate());
expect($elem.html()).toBe('1 day ago');
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d,{format: 'medium'}));
expect($elem.data('format')).toBe("medium");
expect($elem.data('time')).toBe(d.getTime());
expect($elem.html()).toBe('1 day');
});
});
@ -105,6 +115,14 @@ describe("Discourse.Formatter", function() {
expect($elem.html()).toBe("2m");
d = new Date();
$elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d, {format: 'medium', leaveAgo: true}));
$elem.data('time', d.getTime() - 2 * 60 * 1000);
Discourse.Formatter.updateRelativeAge($elem);
expect($elem.html()).toBe("2 minutes ago");
});
});
});

View file

@ -1,3 +1,4 @@
//= require env
//= require ../../app/assets/javascripts/preload_store.js
@ -13,16 +14,17 @@
//= require ../../app/assets/javascripts/external_production/ember.js
//= require ../../app/assets/javascripts/external_production/group-helper.js
//= require ../../app/assets/javascripts/locales/i18n
//= require ../../app/assets/javascripts/locales/date_locales.js
//= require ../../app/assets/javascripts/discourse/helpers/i18n_helpers
//= require ../../app/assets/javascripts/locales/en
//
// Pagedown customizations
//= require ../../app/assets/javascripts/pagedown_custom.js
// The rest of the externals
//= require_tree ../../app/assets/javascripts/external
//= require ../../app/assets/javascripts/locales/i18n
//= require ../../app/assets/javascripts/locales/date_locales.js
//= require ../../app/assets/javascripts/discourse/helpers/i18n_helpers
//= require ../../app/assets/javascripts/locales/en
//= require ../../app/assets/javascripts/discourse
// Stuff we need to load first