mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
correct message bus regression
implement automatically updating dates in list
This commit is contained in:
parent
93aa0a9f39
commit
5f85aaee1d
9 changed files with 200 additions and 29 deletions
22
Guardfile
22
Guardfile
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
68
app/assets/javascripts/discourse/components/formatter.js
Normal file
68
app/assets/javascripts/discourse/components/formatter.js
Normal 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};
|
||||||
|
})();
|
|
@ -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>");
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
63
spec/javascripts/components/formatter_spec.js
Normal file
63
spec/javascripts/components/formatter_spec.js
Normal 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");
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue