correct message bus regression

implement automatically updating dates in list
This commit is contained in:
Sam 2013-06-05 09:32:03 +10:00
parent 93aa0a9f39
commit 5f85aaee1d
9 changed files with 200 additions and 29 deletions

View file

@ -58,19 +58,21 @@ unless ENV["USING_AUTOSPEC"]
end end
end end
def message_bus
MessageBus::Instance.new.tap do |bus|
bus.site_id_lookup do
# this is going to be dev the majority of the time, if you have multisite configured in dev stuff may be different
"default"
end
end
end
module ::Guard module ::Guard
class AutoReload < ::Guard::Guard class AutoReload < ::Guard::Guard
require File.dirname(__FILE__) + '/config/environment' require File.dirname(__FILE__) + '/config/environment'
def self.message_bus
MessageBus::Instance.new.tap do |bus|
bus.site_id_lookup do
# this is going to be dev the majority of the time, if you have multisite configured in dev stuff may be different
"default"
end
end
end
def run_on_change(paths) def run_on_change(paths)
paths.map! do |p| paths.map! do |p|
hash = nil hash = nil
@ -82,7 +84,7 @@ module ::Guard
p = p.sub /^app\/assets\/stylesheets/, "assets" p = p.sub /^app\/assets\/stylesheets/, "assets"
{name: p, hash: hash} {name: p, hash: hash}
end end
message_bus.publish "/file-change", paths self.class.message_bus.publish "/file-change", paths
end end
def run_all def run_all
@ -93,7 +95,7 @@ end
Thread.new do Thread.new do
Listen.to('tmp/') do |modified,added,removed| Listen.to('tmp/') do |modified,added,removed|
modified.each do |m| modified.each do |m|
message_bus.publish "/file-change", ["refresh"] if m =~ /refresh_browser/ Guard::AutoReload.message_bus.publish "/file-change", ["refresh"] if m =~ /refresh_browser/
end end
end end
end end

View file

@ -141,6 +141,10 @@ Discourse = Ember.Application.createWithMixins({
xhr.setRequestHeader('X-CSRF-Token', csrfToken); xhr.setRequestHeader('X-CSRF-Token', csrfToken);
} }
}); });
setInterval(function(){
Discourse.Formatter.updateRelativeAge($('.relative-date'));
},60 * 1000);
}, },
/** /**

View file

@ -0,0 +1,68 @@
Discourse.Formatter = (function(){
var updateRelativeAge, autoUpdatingRelativeAge, relativeAge;
updateRelativeAge = function(elems) {
elems.each(function(){
var $this = $(this);
$this.html(relativeAge(new Date($this.data('time')), $this.data('format')));
});
};
autoUpdatingRelativeAge = function(date,options) {
options = options || {};
var format = options.format || "tiny";
return "<span class='relative-date' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relativeAge(date, options) + "</span>";
};
// mostly lifted from rails with a few amendments
relativeAge = function(date, options) {
options = options || {};
var format = options.format || "tiny";
var distance = Math.round((new Date() - date) / 1000);
var distance_in_minutes = Math.round(distance / 60.0);
var formatted;
var t = function(key,opts){
return Ember.String.i18n("dates." + format + "." + key, opts);
};
switch(true){
case(distance_in_minutes < 1):
formatted = t("less_than_x_minutes", {count: 1});
break;
case(distance_in_minutes >= 1 && distance_in_minutes <= 44):
formatted = t("x_minutes", {count: distance_in_minutes});
break;
case(distance_in_minutes >= 45 && distance_in_minutes <= 89):
formatted = t("about_x_hours", {count: 1});
break;
case(distance_in_minutes >= 90 && distance_in_minutes <= 1439):
formatted = t("about_x_hours", {count: Math.round(distance_in_minutes / 60.0)});
break;
case(distance_in_minutes >= 1440 && distance_in_minutes <= 2519):
formatted = t("x_days", {count: 1});
break;
case(distance_in_minutes >= 2520 && distance_in_minutes <= 129599):
formatted = t("x_days", {count: Math.round(distance_in_minutes / 1440.0)});
break;
case(distance_in_minutes >= 129600 && distance_in_minutes <= 525599):
formatted = t("x_months", {count: Math.round(distance_in_minutes / 43200.0)});
break;
default:
var months = Math.round(distance_in_minutes / 43200.0);
if (months < 24) {
formatted = t("x_months", {count: months});
} else {
formatted = t("over_x_years", {count: Math.round(months / 12.0)});
}
break;
}
return formatted;
};
return {relativeAge: relativeAge, autoUpdatingRelativeAge: autoUpdatingRelativeAge, updateRelativeAge: updateRelativeAge};
})();

View file

@ -173,11 +173,21 @@ Handlebars.registerHelper('avatar', function(user, options) {
@for Handlebars @for Handlebars
**/ **/
Handlebars.registerHelper('unboundDate', function(property, options) { Handlebars.registerHelper('unboundDate', function(property, options) {
var dt; var dt = new Date(Ember.Handlebars.get(this, property, options));
dt = new Date(Ember.Handlebars.get(this, property, options));
return dt.format("long"); return dt.format("long");
}); });
/**
Live refreshing age helper
@method unboundDate
@for Handlebars
**/
Handlebars.registerHelper('unboundAge', function(property, options) {
var dt = new Date(Ember.Handlebars.get(this, property, options));
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(dt));
});
/** /**
Display a date related to an edit of a post Display a date related to an edit of a post
@ -285,7 +295,7 @@ Handlebars.registerHelper('date', function(property, options) {
} }
displayDate = humanized; displayDate = humanized;
if (!leaveAgo) { if (!leaveAgo) {
displayDate = (dt.millisecondsAgo()).duration(); displayDate = (dt.millisecondsAgo()).duration();
} }
} }
return new Handlebars.SafeString("<span class='date' title='" + fullReadable + "'>" + displayDate + "</span>"); return new Handlebars.SafeString("<span class='date' title='" + fullReadable + "'>" + displayDate + "</span>");

View file

@ -63,14 +63,14 @@
{{#if bumped}} {{#if bumped}}
<td class='num activity'> <td class='num activity'>
<a href="{{url}}" {{{bindAttr class=":age ageCold"}}} title='{{i18n first_post}}: {{{unboundDate created_at}}}' >{{{age}}}</a> <a href="{{url}}" {{{bindAttr class=":age ageCold"}}} title='{{i18n first_post}}: {{{unboundDate created_at}}}' >{{unboundAge created_at}}</a>
</td> </td>
<td class='num activity last'> <td class='num activity last'>
<a href="{{lastPostUrl}}" class='age' title='{{i18n last_post}}: {{{unboundDate bumped_at}}}'>{{{bumped_age}}}</a> <a href="{{lastPostUrl}}" class='age' title='{{i18n last_post}}: {{{unboundDate bumped_at}}}'>{{unboundAge bumped_at}}</a>
</td> </td>
{{else}} {{else}}
<td class='num activity'> <td class='num activity'>
<a href="{{url}}" class='age' title='{{i18n first_post}}: {{{unboundDate created_at}}}'>{{{age}}}</a> <a href="{{url}}" class='age' title='{{i18n first_post}}: {{{unboundDate created_at}}}'>{{unboundAge created_at}}</a>
</td> </td>
<td></td> <td></td>
{{/if}} {{/if}}

View file

@ -1,4 +1,3 @@
require_dependency 'age_words'
require_dependency 'pinned_check' require_dependency 'pinned_check'
class ListableTopicSerializer < BasicTopicSerializer class ListableTopicSerializer < BasicTopicSerializer
@ -10,8 +9,6 @@ class ListableTopicSerializer < BasicTopicSerializer
:last_posted_at, :last_posted_at,
:bumped, :bumped,
:bumped_at, :bumped_at,
:bumped_age,
:age,
:unseen, :unseen,
:last_read_post_number, :last_read_post_number,
:unread, :unread,
@ -23,20 +20,10 @@ class ListableTopicSerializer < BasicTopicSerializer
:closed, :closed,
:archived :archived
def age
AgeWords.age_words(Time.now - (object.created_at || Time.now))
end
def bumped def bumped
object.created_at < object.bumped_at object.created_at < object.bumped_at
end end
def bumped_age
return nil if object.bumped_at.blank?
AgeWords.age_words(Time.now - object.bumped_at)
end
alias include_bumped_age? :bumped
def seen def seen
object.user_data.present? object.user_data.present?
end end

View file

@ -7,6 +7,42 @@
en: en:
js: js:
dates:
tiny:
half_a_minute: "< 1m"
less_than_x_seconds:
one: "< 1s"
other: "< %{count}s"
x_seconds:
one: "1s"
other: "%{count}s"
less_than_x_minutes:
one: "< 1m"
other: "< %{count}m"
x_minutes:
one: "1m"
other: "%{count}m"
about_x_hours:
one: "1h"
other: "%{count}h"
x_days:
one: "1d"
other: "%{count}d"
about_x_months:
one: "1mon"
other: "%{count}mon"
x_months:
one: "1mon"
other: "%{count}mon"
about_x_years:
one: "1y"
other: "%{count}y"
over_x_years:
one: "> 1y"
other: "> %{count}y"
almost_x_years:
one: "1y"
other: "%{count}y"
share: share:
topic: 'share a link to this topic' topic: 'share a link to this topic'
post: 'share a link to this post' post: 'share a link to this post'

View file

@ -0,0 +1,63 @@
/*global expect:true describe:true it:true beforeEach:true afterEach:true spyOn:true */
describe("Discourse.Formatter", function() {
describe("relativeTime", function() {
it("can format dates", function() {
var mins_ago = function(mins){
return new Date((new Date()) - mins * 60 * 1000);
};
var formatMins = function(mins) {
return Discourse.Formatter.relativeAge(mins_ago(mins));
};
var formatHours = function(hours) {
return formatMins(hours * 60);
};
var formatDays = function(days) {
return formatHours(days * 24);
};
var formatMonths = function(months) {
return formatDays(months * 30);
};
expect(formatMins(0)).toBe("< 1m");
expect(formatMins(2)).toBe("2m");
expect(formatMins(60)).toBe("1h");
expect(formatHours(4)).toBe("4h");
expect(formatDays(1)).toBe("1d");
expect(formatDays(20)).toBe("20d");
expect(formatMonths(3)).toBe("3mon");
expect(formatMonths(23)).toBe("23mon");
expect(formatMonths(24)).toBe("> 2y");
});
});
describe("autoUpdatingRelativeAge", function(){
it("can format dates", function(){
var d = new Date();
var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d));
expect($elem.data('format')).toBe("tiny");
expect($elem.data('time')).toBe(d.getTime());
});
});
describe("updateRelativeAge", function(){
it("can update relative dates", function(){
var d = new Date();
var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d));
$elem.data('time', d.getTime() - 2 * 60 * 1000);
Discourse.Formatter.updateRelativeAge($elem);
expect($elem.html()).toBe("2m");
});
});
});

View file

@ -22,6 +22,7 @@
//= require ../../app/assets/javascripts/locales/i18n //= require ../../app/assets/javascripts/locales/i18n
//= require ../../app/assets/javascripts/discourse/helpers/i18n_helpers //= 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