FIX: Liking a post shouldn't contract who liked it

This commit is contained in:
Robin Ward
2015-09-17 15:40:15 -04:00
parent 0aee7b8211
commit 4eaaf4198c
9 changed files with 96 additions and 66 deletions

View File

@ -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;
} }

View File

@ -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');
}); });
}); });

View File

@ -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',

View File

@ -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) {

View File

@ -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

View File

@ -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;
}); });
} }
}); });

View File

@ -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}}

View File

@ -1,5 +0,0 @@
import PostMenuComponent from 'discourse/components/post-menu';
Ember.warn("PostMenuView has been deprecated, use PostMenuComponent instead");
export default PostMenuComponent.extend();

View File

@ -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'),