mirror of
https://github.com/discourse/discourse.git
synced 2025-06-11 13:01:32 +08:00
FIX: Liking a post shouldn't contract who liked it
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||||
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||||
|
import { on } from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
export default Ember.Component.extend(StringBuffer, {
|
export default Ember.Component.extend(StringBuffer, {
|
||||||
tagName: 'section',
|
tagName: 'section',
|
||||||
@ -8,32 +9,44 @@ export default Ember.Component.extend(StringBuffer, {
|
|||||||
actionsSummary: Em.computed.alias('post.actionsWithoutLikes'),
|
actionsSummary: Em.computed.alias('post.actionsWithoutLikes'),
|
||||||
emptySummary: Em.computed.empty('actionsSummary'),
|
emptySummary: Em.computed.empty('actionsSummary'),
|
||||||
hidden: Em.computed.and('emptySummary', 'post.notDeleted'),
|
hidden: Em.computed.and('emptySummary', 'post.notDeleted'),
|
||||||
|
usersByType: null,
|
||||||
|
|
||||||
rerenderTriggers: ['actionsSummary.@each', 'actionsSummary.users.length', 'post.deleted'],
|
rerenderTriggers: ['actionsSummary.@each', 'post.deleted'],
|
||||||
|
|
||||||
|
@on('init')
|
||||||
|
initUsersByType() {
|
||||||
|
this.set('usersByType', {});
|
||||||
|
},
|
||||||
|
|
||||||
// This was creating way too many bound ifs and subviews in the handlebars version.
|
// This was creating way too many bound ifs and subviews in the handlebars version.
|
||||||
renderString(buffer) {
|
renderString(buffer) {
|
||||||
|
const usersByType = this.get('usersByType');
|
||||||
|
|
||||||
if (!this.get('emptySummary')) {
|
if (!this.get('emptySummary')) {
|
||||||
this.get('actionsSummary').forEach(function(c) {
|
this.get('actionsSummary').forEach(function(c) {
|
||||||
|
const id = c.get('id');
|
||||||
|
const users = usersByType[id] || [];
|
||||||
|
|
||||||
buffer.push("<div class='post-action'>");
|
buffer.push("<div class='post-action'>");
|
||||||
|
|
||||||
const renderActionIf = function(property, dataAttribute, text) {
|
const renderLink = (dataAttribute, text) => {
|
||||||
if (!c.get(property)) { return; }
|
buffer.push(` <span class='action-link ${dataAttribute}-action'><a href data-${dataAttribute}='${id}'>${text}</a>.</span>`);
|
||||||
buffer.push(" <span class='action-link " + dataAttribute +"-action'><a href data-" + dataAttribute + "='" + c.get('id') + "'>" + text + "</a>.</span>");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO multi line expansion for flags
|
// TODO multi line expansion for flags
|
||||||
let iconsHtml = "";
|
let iconsHtml = "";
|
||||||
if (c.get('usersExpanded')) {
|
if (users.length) {
|
||||||
let postUrl;
|
let postUrl;
|
||||||
c.get('users').forEach(function(u) {
|
users.forEach(function(u) {
|
||||||
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + u.get('username_lower') + "\" data-user-card=\"" + u.get('username_lower') + "\">";
|
const username = u.get('username_lower');
|
||||||
|
|
||||||
|
iconsHtml += `<a href="${Discourse.getURL("/users")}${username}" data-user-card="${username}">`;
|
||||||
if (u.post_url) {
|
if (u.post_url) {
|
||||||
postUrl = postUrl || u.post_url;
|
postUrl = postUrl || u.post_url;
|
||||||
}
|
}
|
||||||
iconsHtml += Discourse.Utilities.avatarImg({
|
iconsHtml += Discourse.Utilities.avatarImg({
|
||||||
size: 'small',
|
size: 'small',
|
||||||
avatarTemplate: u.get('avatarTemplate'),
|
avatarTemplate: u.get('avatar_template'),
|
||||||
title: u.get('username')
|
title: u.get('username')
|
||||||
});
|
});
|
||||||
iconsHtml += "</a>";
|
iconsHtml += "</a>";
|
||||||
@ -45,9 +58,18 @@ export default Ember.Component.extend(StringBuffer, {
|
|||||||
// TODO postUrl might be uninitialized? pick a good default
|
// TODO postUrl might be uninitialized? pick a good default
|
||||||
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
|
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
|
||||||
}
|
}
|
||||||
renderActionIf('usersCollapsed', 'who-acted', c.get('description'));
|
|
||||||
renderActionIf('can_undo', 'undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
|
if (users.length === 0) {
|
||||||
renderActionIf('can_defer_flags', 'defer-flags', I18n.t("post.actions.defer_flags", { count: c.count }));
|
renderLink('who-acted', c.get('description'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.get('can_undo')) {
|
||||||
|
renderLink('undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
|
||||||
|
}
|
||||||
|
if (c.get('can_defer_flags')) {
|
||||||
|
renderLink('defer-flags', I18n.t("post.actions.defer_flags", { count: c.count }));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
buffer.push("</div>");
|
buffer.push("</div>");
|
||||||
});
|
});
|
||||||
@ -79,8 +101,12 @@ export default Ember.Component.extend(StringBuffer, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// User wants to know who actioned it
|
// User wants to know who actioned it
|
||||||
|
const usersByType = this.get('usersByType');
|
||||||
if (actionTypeId = $target.data('who-acted')) {
|
if (actionTypeId = $target.data('who-acted')) {
|
||||||
this.actionTypeById(actionTypeId).loadUsers(post);
|
this.actionTypeById(actionTypeId).loadUsers(post).then(users => {
|
||||||
|
usersByType[actionTypeId] = users;
|
||||||
|
this.rerender();
|
||||||
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,15 +165,12 @@ const PostMenuComponent = Ember.Component.extend(StringBuffer, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
clickLikeCount() {
|
clickLikeCount() {
|
||||||
const likeAction = this.get('post.likeAction');
|
this.sendActionTarget('toggleWhoLiked');
|
||||||
if (likeAction) {
|
},
|
||||||
const users = likeAction.get('users');
|
|
||||||
if (users && users.length) {
|
sendActionTarget(action, arg) {
|
||||||
users.clear();
|
const target = this.get(`${action}Target`);
|
||||||
} else {
|
return target ? target.send(this.get(action), arg) : this.sendAction(action, arg);
|
||||||
likeAction.loadUsers(this.get('post'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
clickReplies() {
|
clickReplies() {
|
||||||
@ -268,13 +265,13 @@ const PostMenuComponent = Ember.Component.extend(StringBuffer, {
|
|||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
if (acted) {
|
if (acted) {
|
||||||
this.sendAction('toggleLike', post);
|
this.sendActionTarget('toggleLike');
|
||||||
$likeButton.removeClass('has-like').addClass('like');
|
$likeButton.removeClass('has-like').addClass('like');
|
||||||
} else {
|
} else {
|
||||||
const scale = [1.0, 1.5];
|
const scale = [1.0, 1.5];
|
||||||
animateHeart($heart, scale[0], scale[1], function() {
|
animateHeart($heart, scale[0], scale[1], function() {
|
||||||
animateHeart($heart, scale[1], scale[0], function() {
|
animateHeart($heart, scale[1], scale[0], function() {
|
||||||
self.sendAction('toggleLike', post);
|
self.sendActionTarget('toggleLike');
|
||||||
$likeButton.removeClass('like').addClass('has-like');
|
$likeButton.removeClass('like').addClass('has-like');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||||
|
|
||||||
export default Ember.Component.extend(StringBuffer, {
|
export default Ember.Component.extend(StringBuffer, {
|
||||||
likedUsers: Ember.computed.alias('post.likeAction.users'),
|
rerenderTriggers: ['users.length'],
|
||||||
rerenderTriggers: ['likedUsers.length'],
|
|
||||||
|
|
||||||
renderString(buffer) {
|
renderString(buffer) {
|
||||||
const likedUsers = this.get('likedUsers');
|
const users = this.get('users');
|
||||||
if (likedUsers && likedUsers.length > 0) {
|
if (users && users.length > 0) {
|
||||||
buffer.push("<div class='who-liked'>");
|
buffer.push("<div class='who-liked'>");
|
||||||
let iconsHtml = "";
|
let iconsHtml = "";
|
||||||
likedUsers.forEach(function(u) {
|
users.forEach(function(u) {
|
||||||
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + u.get('username_lower') + "\" data-user-card=\"" + u.get('username_lower') + "\">";
|
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + u.get('username_lower') + "\" data-user-card=\"" + u.get('username_lower') + "\">";
|
||||||
iconsHtml += Discourse.Utilities.avatarImg({
|
iconsHtml += Discourse.Utilities.avatarImg({
|
||||||
size: 'small',
|
size: 'small',
|
||||||
|
@ -144,13 +144,6 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleLike(post) {
|
|
||||||
const likeAction = post.get('likeAction');
|
|
||||||
if (likeAction && likeAction.get('canToggle')) {
|
|
||||||
likeAction.toggle(post);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
recoverPost(post) {
|
recoverPost(post) {
|
||||||
// Recovering the first post recovers the topic instead
|
// Recovering the first post recovers the topic instead
|
||||||
if (post.get('post_number') === 1) {
|
if (post.get('post_number') === 1) {
|
||||||
|
@ -27,7 +27,7 @@ const bindings = {
|
|||||||
'home': {handler: 'goToFirstPost', anonymous: true},
|
'home': {handler: 'goToFirstPost', anonymous: true},
|
||||||
'j': {handler: 'selectDown', anonymous: true},
|
'j': {handler: 'selectDown', anonymous: true},
|
||||||
'k': {handler: 'selectUp', anonymous: true},
|
'k': {handler: 'selectUp', anonymous: true},
|
||||||
'l': {postAction: 'toggleLike'},
|
'l': {click: '.topic-post.selected button[data-action="like"]'},
|
||||||
'm m': {click: 'div.notification-options li[data-id="0"] a'}, // mark topic as muted
|
'm m': {click: 'div.notification-options li[data-id="0"] a'}, // mark topic as muted
|
||||||
'm r': {click: 'div.notification-options li[data-id="1"] a'}, // mark topic as regular
|
'm r': {click: 'div.notification-options li[data-id="1"] a'}, // mark topic as regular
|
||||||
'm t': {click: 'div.notification-options li[data-id="2"] a'}, // mark topic as tracking
|
'm t': {click: 'div.notification-options li[data-id="2"] a'}, // mark topic as tracking
|
||||||
|
@ -17,9 +17,6 @@ export default RestModel.extend({
|
|||||||
}
|
}
|
||||||
}.property('count', 'acted', 'actionType'),
|
}.property('count', 'acted', 'actionType'),
|
||||||
|
|
||||||
usersCollapsed: Em.computed.not('usersExpanded'),
|
|
||||||
usersExpanded: Em.computed.gt('users.length', 0),
|
|
||||||
|
|
||||||
canToggle: function() {
|
canToggle: function() {
|
||||||
return this.get('can_undo') || this.get('can_act');
|
return this.get('can_undo') || this.get('can_act');
|
||||||
}.property('can_undo', 'can_act'),
|
}.property('can_undo', 'can_act'),
|
||||||
@ -32,17 +29,15 @@ export default RestModel.extend({
|
|||||||
can_act: true,
|
can_act: true,
|
||||||
can_undo: false
|
can_undo: false
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.get('usersExpanded')) {
|
|
||||||
this.get('users').removeObject(Discourse.User.current());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
toggle: function(post) {
|
toggle: function(post) {
|
||||||
if (!this.get('acted')) {
|
if (!this.get('acted')) {
|
||||||
this.act(post);
|
this.act(post);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
this.undo(post);
|
this.undo(post);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -66,14 +61,8 @@ export default RestModel.extend({
|
|||||||
this.set('can_defer_flags',false);
|
this.set('can_defer_flags',false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add ourselves to the users who liked it if present
|
|
||||||
if (this.get('usersExpanded')) {
|
|
||||||
this.get('users').addObject(Discourse.User.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create our post action
|
// Create our post action
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
return Discourse.ajax("/post_actions", {
|
return Discourse.ajax("/post_actions", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: {
|
data: {
|
||||||
@ -121,16 +110,11 @@ export default RestModel.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadUsers: function(post) {
|
loadUsers(post) {
|
||||||
const self = this;
|
return Discourse.ajax("/post_actions/users", {
|
||||||
Discourse.ajax("/post_actions/users", {
|
data: { id: post.get('id'), post_action_type_id: this.get('id') }
|
||||||
data: {
|
|
||||||
id: post.get('id'),
|
|
||||||
post_action_type_id: this.get('id')
|
|
||||||
}
|
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
const users = [];
|
const users = [];
|
||||||
self.set('users', users);
|
|
||||||
result.forEach(function(user) {
|
result.forEach(function(user) {
|
||||||
if (user.id === Discourse.User.currentProp('id')) {
|
if (user.id === Discourse.User.currentProp('id')) {
|
||||||
users.pushObject(Discourse.User.current());
|
users.pushObject(Discourse.User.current());
|
||||||
@ -138,6 +122,7 @@ export default RestModel.extend({
|
|||||||
users.pushObject(Discourse.User.create(user));
|
users.pushObject(Discourse.User.create(user));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return users;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -104,16 +104,19 @@
|
|||||||
recoverPost="recoverPost"
|
recoverPost="recoverPost"
|
||||||
deletePost="deletePost"
|
deletePost="deletePost"
|
||||||
toggleLike="toggleLike"
|
toggleLike="toggleLike"
|
||||||
|
toggleLikeTarget=view
|
||||||
showFlags="showFlags"
|
showFlags="showFlags"
|
||||||
editPost="editPost"
|
editPost="editPost"
|
||||||
toggleBookmark="toggleBookmark"
|
toggleBookmark="toggleBookmark"
|
||||||
toggleWiki="toggleWiki"
|
toggleWiki="toggleWiki"
|
||||||
togglePostType="togglePostType"
|
togglePostType="togglePostType"
|
||||||
rebakePost="rebakePost"
|
rebakePost="rebakePost"
|
||||||
unhidePost="unhidePost"}}
|
unhidePost="unhidePost"
|
||||||
|
toggleWhoLiked="toggleWhoLiked"
|
||||||
|
toggleWhoLikedTarget=view}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{who-liked post=this}}
|
{{who-liked users=view.likedUsers}}
|
||||||
{{#if replies}}
|
{{#if replies}}
|
||||||
<section class='embedded-posts bottom'>
|
<section class='embedded-posts bottom'>
|
||||||
{{#each reply in replies}}
|
{{#each reply in replies}}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
import PostMenuComponent from 'discourse/components/post-menu';
|
|
||||||
|
|
||||||
Ember.warn("PostMenuView has been deprecated, use PostMenuComponent instead");
|
|
||||||
|
|
||||||
export default PostMenuComponent.extend();
|
|
@ -1,7 +1,7 @@
|
|||||||
import ScreenTrack from 'discourse/lib/screen-track';
|
import ScreenTrack from 'discourse/lib/screen-track';
|
||||||
import { number } from 'discourse/lib/formatter';
|
import { number } from 'discourse/lib/formatter';
|
||||||
import DiscourseURL from 'discourse/lib/url';
|
import DiscourseURL from 'discourse/lib/url';
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
|
||||||
import { fmt } from 'discourse/lib/computed';
|
import { fmt } from 'discourse/lib/computed';
|
||||||
|
|
||||||
const DAY = 60 * 50 * 1000;
|
const DAY = 60 * 50 * 1000;
|
||||||
@ -18,8 +18,13 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
|||||||
'whisper'],
|
'whisper'],
|
||||||
|
|
||||||
post: Ember.computed.alias('content'),
|
post: Ember.computed.alias('content'),
|
||||||
|
|
||||||
postElementId: fmt('post.post_number', 'post_%@'),
|
postElementId: fmt('post.post_number', 'post_%@'),
|
||||||
|
likedUsers: null,
|
||||||
|
|
||||||
|
@on('init')
|
||||||
|
initLikedUsers() {
|
||||||
|
this.set('likedUsers', []);
|
||||||
|
},
|
||||||
|
|
||||||
@computed('post.post_type')
|
@computed('post.post_type')
|
||||||
whisper(postType) {
|
whisper(postType) {
|
||||||
@ -197,6 +202,33 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
toggleLike() {
|
||||||
|
const currentUser = this.get('controller.currentUser');
|
||||||
|
const post = this.get('post');
|
||||||
|
const likeAction = post.get('likeAction');
|
||||||
|
if (likeAction && likeAction.get('canToggle')) {
|
||||||
|
const users = this.get('likedUsers');
|
||||||
|
if (likeAction.toggle(post) && users.length) {
|
||||||
|
users.addObject(currentUser);
|
||||||
|
} else {
|
||||||
|
users.removeObject(currentUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleWhoLiked() {
|
||||||
|
const post = this.get('post');
|
||||||
|
const likeAction = post.get('likeAction');
|
||||||
|
if (likeAction) {
|
||||||
|
const users = this.get('likedUsers');
|
||||||
|
if (users.length) {
|
||||||
|
users.clear();
|
||||||
|
} else {
|
||||||
|
likeAction.loadUsers(post).then(newUsers => this.set('likedUsers', newUsers));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Toggle the replies this post is a reply to
|
// Toggle the replies this post is a reply to
|
||||||
toggleReplyHistory(post) {
|
toggleReplyHistory(post) {
|
||||||
const replyHistory = post.get('replyHistory'),
|
const replyHistory = post.get('replyHistory'),
|
||||||
|
Reference in New Issue
Block a user