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, relativeAgeMedium, relativeAgeMediumSpan, longDate, toTitleCase,
shortDate; 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){ shortDate = function(date){
return moment(date).format(shortDateFormat); return moment(date).shortDate();
}; };
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript // http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
// TODO: locale support ? // TODO: locale support ?
toTitleCase = function toTitleCase(str) toTitleCase = function toTitleCase(str)
@ -23,14 +18,14 @@ Discourse.Formatter = (function(){
} }
longDate = function(dt) { longDate = function(dt) {
return moment(dt).format(longDateFormat); return moment(dt).longDate();
}; };
updateRelativeAge = function(elems) { updateRelativeAge = function(elems) {
// jQuery .each // jQuery .each
elems.each(function(){ elems.each(function(){
var $this = $(this); 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 || {}; options = options || {};
var format = options.format || "tiny"; 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()) { if ((new Date()).getFullYear() !== date.getFullYear()) {
displayDate = shortDate(date); displayDate = shortDate(date);
} else { } else {
displayDate = moment(date).format(shortDateNoYearFormat); displayDate = moment(date).shortDateNoYear();
} }
} else { } else {
displayDate = relativeAgeMediumSpan(distance, leaveAgo); displayDate = relativeAgeMediumSpan(distance, leaveAgo);
@ -160,6 +165,8 @@ Discourse.Formatter = (function(){
return relativeAgeTiny(date, options); return relativeAgeTiny(date, options);
} else if (format === "medium") { } else if (format === "medium") {
return relativeAgeMedium(date, options); return relativeAgeMedium(date, options);
} else if (format === 'medium-with-ago') {
return relativeAgeMedium(date, _.extend(options, {format: 'medium', leaveAgo: true}));
} }
return "UNKNOWN FORMAT"; return "UNKNOWN FORMAT";

View file

@ -212,7 +212,7 @@ Handlebars.registerHelper('unboundAge', function(property, options) {
Handlebars.registerHelper('editDate', function(property, options) { Handlebars.registerHelper('editDate', function(property, options) {
// autoupdating this is going to be painful // autoupdating this is going to be painful
var date = new Date(Ember.Handlebars.get(this, property, options)); 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) { if (val) {
date = new Date(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: en:
js: js:
dates: dates:
short_date_no_year: "D MMM"
short_date: "D MMM, YYYY"
long_date: "MMMM D, YYYY h:mma"
tiny: tiny:
half_a_minute: "< 1m" half_a_minute: "< 1m"
less_than_x_seconds: less_than_x_seconds:

View file

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

View file

@ -18,11 +18,26 @@ module JsLocaleHelper
result = generate_message_format(message_formats, locale_str) result = generate_message_format(message_formats, locale_str)
result << "I18n.translations = #{translations.to_json};\n" 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_locale(locale_str)
result << moment_formats
result result
end 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) def self.moment_locale(locale_str)
filename = Rails.root + "lib/javascript/moment_locale/#{locale_str}.js" filename = Rails.root + "lib/javascript/moment_locale/#{locale_str}.js"
if File.exists?(filename) if File.exists?(filename)

View file

@ -85,12 +85,22 @@ describe("Discourse.Formatter", function() {
describe("autoUpdatingRelativeAge", function(){ describe("autoUpdatingRelativeAge", function(){
it("can format dates", function(){ it("can format dates", function(){
var d = new Date(); var d = moment().subtract('days',1).toDate();
var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d)); var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d));
expect($elem.data('format')).toBe("tiny"); expect($elem.data('format')).toBe("tiny");
expect($elem.data('time')).toBe(d.getTime()); 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"); 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 env
//= require ../../app/assets/javascripts/preload_store.js //= 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/ember.js
//= require ../../app/assets/javascripts/external_production/group-helper.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 // Pagedown customizations
//= require ../../app/assets/javascripts/pagedown_custom.js //= require ../../app/assets/javascripts/pagedown_custom.js
// The rest of the externals // The rest of the externals
//= require_tree ../../app/assets/javascripts/external //= 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 //= require ../../app/assets/javascripts/discourse
// Stuff we need to load first // Stuff we need to load first