FEATURE: live delete / recover

BUGFIX: total post count could be smaller than filtered posts count
BUGFIX: filteredPostsCount not correctly defined
This commit is contained in:
Sam 2014-06-04 14:10:34 +10:00
parent e307bad89a
commit cab589ec67
4 changed files with 107 additions and 6 deletions

View file

@ -265,6 +265,12 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
return (this.get('progressPosition') < 2);
}.property('progressPosition'),
filteredPostCountChanged: function(){
if(this.get('postStream.filteredPostsCount') < this.get('progressPosition')){
this.set('progressPosition', this.get('postStream.filteredPostsCount'));
}
}.observes('postStream.filteredPostsCount'),
jumpBottomDisabled: function() {
return this.get('progressPosition') >= this.get('postStream.filteredPostsCount') ||
this.get('progressPosition') >= this.get('highest_post_number');
@ -410,6 +416,16 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
return;
}
if (data.type === "deleted"){
postStream.triggerDeletedPost(data.id, data.post_number);
return;
}
if (data.type === "recovered"){
postStream.triggerRecoveredPost(data.id, data.post_number);
return;
}
// Add the new post into the stream
postStream.triggerNewPostInStream(data.id);
});

View file

@ -17,14 +17,18 @@ Discourse.PostStream = Em.Object.extend({
notLoading: Em.computed.not('loading'),
filteredPostsCount: Em.computed.alias('stream.length'),
filteredPostsCount: function(){
return this.get("stream").length;
}.property("stream.@each"),
/**
Have we loaded any posts?
@property hasPosts
**/
hasPosts: Em.computed.gt('posts.length', 0),
hasPosts: function(){
return this.get('posts.length') > 0;
}.property("posts.@each"),
/**
Do we have a stream list of post ids?
@ -55,7 +59,7 @@ Discourse.PostStream = Em.Object.extend({
firstPostPresent: function() {
if (!this.get('hasLoadedData')) { return false; }
return !!this.get('posts').findProperty('id', this.get('firstPostId'));
}.property('hasLoadedData', 'posts.[]', 'firstPostId'),
}.property('hasLoadedData', 'posts.@each', 'firstPostId'),
firstPostNotLoaded: Em.computed.not('firstPostPresent'),
@ -480,9 +484,13 @@ Discourse.PostStream = Em.Object.extend({
if (Em.isEmpty(posts)) { return; }
var postIds = posts.map(function (p) { return p.get('id'); });
var identityMap = this.get('postIdentityMap');
this.get('stream').removeObjects(postIds);
this.get('posts').removeObjects(posts);
postIds.forEach(function(id){
identityMap.remove(id);
});
},
/**
@ -518,17 +526,78 @@ Discourse.PostStream = Em.Object.extend({
}
},
triggerRecoveredPost: function(postId){
var self = this,
postIdentityMap = this.get('postIdentityMap'),
existing = postIdentityMap.get(postId);
if(existing){
this.triggerChangedPost(postId, new Date());
} else {
// need to insert into stream
var url = "/posts/" + postId;
Discourse.ajax(url).then(function(p){
var post = Discourse.Post.create(p);
var stream = self.get("stream");
var posts = self.get("posts");
self.storePost(post);
// we need to zip this into the stream
var index = 0;
stream.forEach(function(postId){
if(postId < p.id){
index+= 1;
}
});
stream.insertAt(index, p.id);
index = 0;
posts.forEach(function(_post){
if(_post.id < p.id){
index+= 1;
}
});
if(index < posts.length){
posts.insertAt(index, post);
} else {
if(post.post_number < posts[posts.length-1].post_number + 5){
self.appendMore();
}
}
});
}
},
triggerDeletedPost: function(postId){
var self = this,
postIdentityMap = this.get('postIdentityMap'),
existing = postIdentityMap.get(postId);
if(existing){
var url = "/posts/" + postId;
Discourse.ajax(url).then(
function(p){
self.storePost(Discourse.Post.create(p));
},
function(){
self.removePosts([existing]);
});
}
},
triggerChangedPost: function(postId, updatedAt) {
if (!postId) { return; }
var postIdentityMap = this.get('postIdentityMap'),
existing = postIdentityMap.get(postId),
postStream = this;
self = this;
if (existing && existing.updated_at !== updatedAt) {
var url = "/posts/" + postId;
Discourse.ajax(url).then(function(p){
postStream.storePost(Discourse.Post.create(p));
self.storePost(Discourse.Post.create(p));
});
}
},

View file

@ -25,7 +25,7 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
updateBar: function() {
Em.run.scheduleOnce('afterRender', this, '_updateProgressBar');
}.observes('controller.streamPercentage'),
}.observes('controller.streamPercentage', 'postStream.stream.@each'),
_updateProgressBar: function() {
var $topicProgress = this._topicProgress;

View file

@ -48,6 +48,7 @@ class PostDestroyer
def staff_recovered
@post.recover!
publish("recovered")
end
# When a post is properly deleted. Well, it's still soft deleted, but it will no longer
@ -68,6 +69,21 @@ class PostDestroyer
@post.topic.trash!(@user) if @post.topic and @post.post_number == 1
update_associated_category_latest_topic
end
publish("deleted")
end
def publish(message)
# edge case, topic is already destroyed
return unless @post.topic
MessageBus.publish("/topic/#{@post.topic_id}",{
id: @post.id,
post_number: @post.post_number,
updated_at: @post.updated_at,
type: message
},
group_ids: @post.topic.secure_group_ids
)
end
# When a user 'deletes' their own post. We just change the text.