FEATURE: remove bookmark button in activity feed
This commit is contained in:
parent
9125453628
commit
bc3de84ebf
|
@ -102,9 +102,8 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
presentName: Em.computed.any('name', 'username'),
|
presentName: Em.computed.any('name', 'username'),
|
||||||
targetDisplayName: Em.computed.any('target_name', 'target_username'),
|
targetDisplayName: Em.computed.any('target_name', 'target_username'),
|
||||||
actingDisplayName: Em.computed.any('acting_name', 'acting_username'),
|
actingDisplayName: Em.computed.any('acting_name', 'acting_username'),
|
||||||
|
|
||||||
|
|
||||||
targetUserUrl: Discourse.computed.url('target_username', '/users/%@'),
|
targetUserUrl: Discourse.computed.url('target_username', '/users/%@'),
|
||||||
|
|
||||||
usernameLower: function() {
|
usernameLower: function() {
|
||||||
return this.get('username').toLowerCase();
|
return this.get('username').toLowerCase();
|
||||||
}.property('username'),
|
}.property('username'),
|
||||||
|
@ -122,6 +121,7 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
replyType: Em.computed.equal('action_type', UserActionTypes.replies),
|
replyType: Em.computed.equal('action_type', UserActionTypes.replies),
|
||||||
postType: Em.computed.equal('action_type', UserActionTypes.posts),
|
postType: Em.computed.equal('action_type', UserActionTypes.posts),
|
||||||
topicType: Em.computed.equal('action_type', UserActionTypes.topics),
|
topicType: Em.computed.equal('action_type', UserActionTypes.topics),
|
||||||
|
bookmarkType: Em.computed.equal('action_type', UserActionTypes.bookmarks),
|
||||||
messageSentType: Em.computed.equal('action_type', UserActionTypes.messages_sent),
|
messageSentType: Em.computed.equal('action_type', UserActionTypes.messages_sent),
|
||||||
messageReceivedType: Em.computed.equal('action_type', UserActionTypes.messages_received),
|
messageReceivedType: Em.computed.equal('action_type', UserActionTypes.messages_received),
|
||||||
mentionType: Em.computed.equal('action_type', UserActionTypes.mentions),
|
mentionType: Em.computed.equal('action_type', UserActionTypes.mentions),
|
||||||
|
@ -168,7 +168,11 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return rval;
|
return rval;
|
||||||
}.property("childGroups"),
|
}.property("childGroups",
|
||||||
|
"childGroups.likes.items", "childGroups.likes.items.@each",
|
||||||
|
"childGroups.stars.items", "childGroups.stars.items.@each",
|
||||||
|
"childGroups.edits.items", "childGroups.edits.items.@each",
|
||||||
|
"childGroups.bookmarks.items", "childGroups.bookmarks.items.@each"),
|
||||||
|
|
||||||
switchToActing: function() {
|
switchToActing: function() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
|
@ -193,7 +197,6 @@ Discourse.UserAction.reopenClass({
|
||||||
var current;
|
var current;
|
||||||
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
||||||
current = Discourse.UserAction.create(item);
|
current = Discourse.UserAction.create(item);
|
||||||
current.setProperties({action_type: null, description: null});
|
|
||||||
item.switchToActing();
|
item.switchToActing();
|
||||||
current.addChild(item);
|
current.addChild(item);
|
||||||
} else {
|
} else {
|
||||||
|
@ -217,11 +220,13 @@ Discourse.UserAction.reopenClass({
|
||||||
TYPES: UserActionTypes,
|
TYPES: UserActionTypes,
|
||||||
TYPES_INVERTED: InvertedActionTypes,
|
TYPES_INVERTED: InvertedActionTypes,
|
||||||
|
|
||||||
TO_COLLAPSE: [UserActionTypes.likes_given,
|
TO_COLLAPSE: [
|
||||||
|
UserActionTypes.likes_given,
|
||||||
UserActionTypes.likes_received,
|
UserActionTypes.likes_received,
|
||||||
UserActionTypes.starred,
|
UserActionTypes.starred,
|
||||||
UserActionTypes.edits,
|
UserActionTypes.edits,
|
||||||
UserActionTypes.bookmarks],
|
UserActionTypes.bookmarks
|
||||||
|
],
|
||||||
|
|
||||||
TO_SHOW: [
|
TO_SHOW: [
|
||||||
UserActionTypes.likes_given,
|
UserActionTypes.likes_given,
|
||||||
|
@ -234,6 +239,3 @@ Discourse.UserAction.reopenClass({
|
||||||
]
|
]
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,30 @@ Discourse.UserStream = Discourse.Model.extend({
|
||||||
return this.findItems();
|
return this.findItems();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
remove: function(userAction) {
|
||||||
|
// 1) remove the user action from the child groups
|
||||||
|
this.get("content").forEach(function (ua) {
|
||||||
|
["likes", "stars", "edits", "bookmarks"].forEach(function (group) {
|
||||||
|
var items = ua.get("childGroups." + group + ".items");
|
||||||
|
if (items) {
|
||||||
|
items.removeObject(userAction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2) remove the parents that have no children
|
||||||
|
var content = this.get("content").filter(function (ua) {
|
||||||
|
return ["likes", "stars", "edits", "bookmarks"].any(function (group) {
|
||||||
|
return ua.get("childGroups." + group + ".items.length") > 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setProperties({
|
||||||
|
content: content,
|
||||||
|
itemsLoaded: content.length
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
findItems: function() {
|
findItems: function() {
|
||||||
var userStream = this;
|
var userStream = this;
|
||||||
if(this.get('loading')) { return Ember.RSVP.reject(); }
|
if(this.get('loading')) { return Ember.RSVP.reject(); }
|
||||||
|
|
|
@ -24,6 +24,25 @@ Discourse.UserActivityStreamRoute = Discourse.Route.extend({
|
||||||
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
|
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
|
||||||
|
|
||||||
this.controllerFor('user').set('indexStream', !this.get('userActionType'));
|
this.controllerFor('user').set('indexStream', !this.get('userActionType'));
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
removeBookmark: function(userAction) {
|
||||||
|
var self = this;
|
||||||
|
Discourse.ajax("/posts/by_number/" + userAction.topic_id + "/" + userAction.post_number + "/bookmarks/remove", { type: "PUT" })
|
||||||
|
.then(function() {
|
||||||
|
// remove the user action from the stream
|
||||||
|
self.modelFor("user").get("stream").remove(userAction);
|
||||||
|
// update the counts
|
||||||
|
self.modelFor("user").get("stats").forEach(function (stat) {
|
||||||
|
if (stat.get("action_type") === userAction.action_type) {
|
||||||
|
stat.decrementProperty("count");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,17 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="type">{{unbound descriptionHtml}}</span>
|
<span class="type">{{unbound descriptionHtml}}</span>
|
||||||
</div>
|
</div>
|
||||||
<p class='excerpt'>
|
<p class='excerpt'>{{{unbound excerpt}}}</p>
|
||||||
{{{unbound excerpt}}}
|
|
||||||
</p>
|
|
||||||
{{#groupedEach children}}
|
{{#groupedEach children}}
|
||||||
<div class='child-actions'>
|
<div class='child-actions'>
|
||||||
<i class="icon {{unbound icon}}"></i>
|
<i class="icon {{unbound icon}}"></i>
|
||||||
{{#groupedEach items}}
|
{{#groupedEach items}}
|
||||||
|
{{#if bookmarkType}}
|
||||||
|
<button class="btn btn-default remove-bookmark" {{action removeBookmark this}}>
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
{{i18n "bookmarks.remove"}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
||||||
{{#if edit_reason}} — <span class="edit-reason">{{unbound edit_reason}}</span>{{/if}}
|
{{#if edit_reason}} — <span class="edit-reason">{{unbound edit_reason}}</span>{{/if}}
|
||||||
{{/groupedEach}}
|
{{/groupedEach}}
|
||||||
|
|
|
@ -10,7 +10,7 @@ Discourse.ActivityFilterView = Ember.Component.extend({
|
||||||
tagName: 'li',
|
tagName: 'li',
|
||||||
classNameBindings: ['active', 'noGlyph'],
|
classNameBindings: ['active', 'noGlyph'],
|
||||||
|
|
||||||
shouldRerender: Discourse.View.renderIfChanged('count'),
|
shouldRerender: Discourse.View.renderIfChanged('content.count', 'count'),
|
||||||
noGlyph: Em.computed.empty('icon'),
|
noGlyph: Em.computed.empty('icon'),
|
||||||
|
|
||||||
active: function() {
|
active: function() {
|
||||||
|
@ -23,11 +23,10 @@ Discourse.ActivityFilterView = Ember.Component.extend({
|
||||||
}.property('userActionType', 'indexStream'),
|
}.property('userActionType', 'indexStream'),
|
||||||
|
|
||||||
activityCount: function() {
|
activityCount: function() {
|
||||||
return this.get('content.count') || this.get('count');
|
return this.get('content.count') || this.get('count') || 0;
|
||||||
}.property('content.count', 'count'),
|
}.property('content.count', 'count'),
|
||||||
|
|
||||||
typeKey: function() {
|
typeKey: function() {
|
||||||
|
|
||||||
var actionType = this.get('content.action_type');
|
var actionType = this.get('content.action_type');
|
||||||
if (actionType === Discourse.UserAction.TYPES.messages_received) { return ""; }
|
if (actionType === Discourse.UserAction.TYPES.messages_received) { return ""; }
|
||||||
|
|
||||||
|
@ -52,23 +51,17 @@ Discourse.ActivityFilterView = Ember.Component.extend({
|
||||||
if (icon) {
|
if (icon) {
|
||||||
buffer.push("<i class='glyph fa fa-" + icon + "'></i> ");
|
buffer.push("<i class='glyph fa fa-" + icon + "'></i> ");
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.push(this.get('description') + " <span class='count'>(" + this.get('activityCount') + ")</span>");
|
buffer.push(this.get('description') + " <span class='count'>(" + this.get('activityCount') + ")</span>");
|
||||||
buffer.push("<span class='fa fa-chevron-right'></span></a>");
|
buffer.push("<span class='fa fa-chevron-right'></span></a>");
|
||||||
},
|
},
|
||||||
|
|
||||||
icon: function() {
|
icon: function() {
|
||||||
switch(parseInt(this.get('content.action_type'), 10)) {
|
switch(parseInt(this.get('content.action_type'), 10)) {
|
||||||
case Discourse.UserAction.TYPES.likes_received:
|
case Discourse.UserAction.TYPES.likes_received: return "heart";
|
||||||
return "heart";
|
case Discourse.UserAction.TYPES.bookmarks: return "bookmark";
|
||||||
case Discourse.UserAction.TYPES.bookmarks:
|
case Discourse.UserAction.TYPES.edits: return "pencil";
|
||||||
return "bookmark";
|
case Discourse.UserAction.TYPES.replies: return "reply";
|
||||||
case Discourse.UserAction.TYPES.edits:
|
case Discourse.UserAction.TYPES.starred: return "star";
|
||||||
return "pencil";
|
|
||||||
case Discourse.UserAction.TYPES.replies:
|
|
||||||
return "reply";
|
|
||||||
case Discourse.UserAction.TYPES.starred:
|
|
||||||
return "star";
|
|
||||||
}
|
}
|
||||||
}.property("content.action_type")
|
}.property("content.action_type")
|
||||||
|
|
||||||
|
|
|
@ -344,5 +344,9 @@
|
||||||
background-color: scale-color($highlight, $lightness: 25%);
|
background-color: scale-color($highlight, $lightness: 25%);
|
||||||
padding: 3px 5px 5px 5px;
|
padding: 3px 5px 5px 5px;
|
||||||
}
|
}
|
||||||
|
.remove-bookmark {
|
||||||
|
float: right;
|
||||||
|
margin-top: -4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,5 +249,9 @@
|
||||||
background-color: scale-color($highlight, $lightness: 50%);
|
background-color: scale-color($highlight, $lightness: 50%);
|
||||||
padding: 3px 5px 5px 5px;
|
padding: 3px 5px 5px 5px;
|
||||||
}
|
}
|
||||||
|
.remove-bookmark {
|
||||||
|
float: right !important;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,14 @@ class PostsController < ApplicationController
|
||||||
display_post(post)
|
display_post(post)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_bookmark_by_number
|
||||||
|
if current_user
|
||||||
|
post = find_post_from_params_by_number
|
||||||
|
PostAction.remove_act(current_user, post, PostActionType.types[:bookmark])
|
||||||
|
end
|
||||||
|
render nothing: true
|
||||||
|
end
|
||||||
|
|
||||||
def reply_history
|
def reply_history
|
||||||
post = find_post_from_params
|
post = find_post_from_params
|
||||||
render_serialized(post.reply_history, PostSerializer)
|
render_serialized(post.reply_history, PostSerializer)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class UserActionsController < ApplicationController
|
class UserActionsController < ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
params.require(:username)
|
params.require(:username)
|
||||||
params.permit(:filter, :offset)
|
params.permit(:filter, :offset)
|
||||||
|
@ -24,9 +25,4 @@ class UserActionsController < ApplicationController
|
||||||
render json: UserAction.stream_item(params[:id], guardian)
|
render json: UserAction.stream_item(params[:id], guardian)
|
||||||
end
|
end
|
||||||
|
|
||||||
def private_messages
|
|
||||||
# todo
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -103,6 +103,7 @@ SQL
|
||||||
|
|
||||||
builder = SqlBuilder.new("
|
builder = SqlBuilder.new("
|
||||||
SELECT
|
SELECT
|
||||||
|
a.id,
|
||||||
t.title, a.action_type, a.created_at, t.id topic_id,
|
t.title, a.action_type, a.created_at, t.id topic_id,
|
||||||
a.user_id AS target_user_id, au.name AS target_name, au.username AS target_username,
|
a.user_id AS target_user_id, au.name AS target_name, au.username AS target_username,
|
||||||
coalesce(p.post_number, 1) post_number,
|
coalesce(p.post_number, 1) post_number,
|
||||||
|
|
|
@ -68,8 +68,12 @@ class UserActionSerializer < ApplicationSerializer
|
||||||
object.post_type == Post.types[:moderator_action]
|
object.post_type == Post.types[:moderator_action]
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit_reason
|
def include_reply_to_post_number?
|
||||||
object.edit_reason if object.action_type == UserAction::EDIT
|
object.action_type == UserAction::REPLY
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_edit_reason?
|
||||||
|
object.action_type == UserAction::EDIT
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -146,6 +146,7 @@ en:
|
||||||
created: "you've bookmarked this post"
|
created: "you've bookmarked this post"
|
||||||
not_bookmarked: "you've read this post; click to bookmark it"
|
not_bookmarked: "you've read this post; click to bookmark it"
|
||||||
last_read: "this is the last post you've read; click to bookmark it"
|
last_read: "this is the last post you've read; click to bookmark it"
|
||||||
|
remove: "Remove Bookmark"
|
||||||
|
|
||||||
new_topics_inserted: "{{count}} new topics."
|
new_topics_inserted: "{{count}} new topics."
|
||||||
show_new_topics: "Click to show."
|
show_new_topics: "Click to show."
|
||||||
|
|
|
@ -214,6 +214,7 @@ Discourse::Application.routes.draw do
|
||||||
post "uploads" => "uploads#create"
|
post "uploads" => "uploads#create"
|
||||||
|
|
||||||
get "posts/by_number/:topic_id/:post_number" => "posts#by_number"
|
get "posts/by_number/:topic_id/:post_number" => "posts#by_number"
|
||||||
|
put "posts/by_number/:topic_id/:post_number/bookmarks/remove" => "posts#remove_bookmark_by_number"
|
||||||
get "posts/:id/reply-history" => "posts#reply_history"
|
get "posts/:id/reply-history" => "posts#reply_history"
|
||||||
|
|
||||||
resources :groups do
|
resources :groups do
|
||||||
|
|
|
@ -288,9 +288,13 @@ describe PostsController do
|
||||||
let(:post) { Fabricate(:post, user: log_in) }
|
let(:post) { Fabricate(:post, user: log_in) }
|
||||||
|
|
||||||
it "raises an error if the user doesn't have permission to see the post" do
|
it "raises an error if the user doesn't have permission to see the post" do
|
||||||
Guardian.any_instance.expects(:can_see?).with(post).returns(false)
|
Guardian.any_instance.expects(:can_see?).with(post).returns(false).twice
|
||||||
|
|
||||||
xhr :put, :bookmark, post_id: post.id, bookmarked: 'true'
|
xhr :put, :bookmark, post_id: post.id, bookmarked: 'true'
|
||||||
response.should be_forbidden
|
response.should be_forbidden
|
||||||
|
|
||||||
|
xhr :put, :remove_bookmark_by_number, topic_id: post.topic_id, post_number: post.post_number
|
||||||
|
response.should be_forbidden
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a bookmark' do
|
it 'creates a bookmark' do
|
||||||
|
@ -303,6 +307,11 @@ describe PostsController do
|
||||||
xhr :put, :bookmark, post_id: post.id
|
xhr :put, :bookmark, post_id: post.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'removes a bookmark using the topic_id and the post_number' do
|
||||||
|
PostAction.expects(:remove_act).with(post.user, post, PostActionType.types[:bookmark])
|
||||||
|
xhr :put, :remove_bookmark_by_number, topic_id: post.topic_id, post_number: post.post_number
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue