diff --git a/app/assets/javascripts/discourse/components/actions-summary.js.es6 b/app/assets/javascripts/discourse/components/actions-summary.js.es6 index bac5779d496..f817f6da58d 100644 --- a/app/assets/javascripts/discourse/components/actions-summary.js.es6 +++ b/app/assets/javascripts/discourse/components/actions-summary.js.es6 @@ -1,6 +1,7 @@ import StringBuffer from 'discourse/mixins/string-buffer'; import { iconHTML } from 'discourse/helpers/fa-icon'; import { autoUpdatingRelativeAge } from 'discourse/lib/formatter'; +import { on } from 'ember-addons/ember-computed-decorators'; export default Ember.Component.extend(StringBuffer, { tagName: 'section', @@ -8,32 +9,44 @@ export default Ember.Component.extend(StringBuffer, { actionsSummary: Em.computed.alias('post.actionsWithoutLikes'), emptySummary: Em.computed.empty('actionsSummary'), 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. renderString(buffer) { + const usersByType = this.get('usersByType'); + if (!this.get('emptySummary')) { this.get('actionsSummary').forEach(function(c) { + const id = c.get('id'); + const users = usersByType[id] || []; + buffer.push("
"); - const renderActionIf = function(property, dataAttribute, text) { - if (!c.get(property)) { return; } - buffer.push(" " + text + "."); + const renderLink = (dataAttribute, text) => { + buffer.push(` ${text}.`); }; // TODO multi line expansion for flags let iconsHtml = ""; - if (c.get('usersExpanded')) { + if (users.length) { let postUrl; - c.get('users').forEach(function(u) { - iconsHtml += ""; + users.forEach(function(u) { + const username = u.get('username_lower'); + + iconsHtml += ``; if (u.post_url) { postUrl = postUrl || u.post_url; } iconsHtml += Discourse.Utilities.avatarImg({ size: 'small', - avatarTemplate: u.get('avatarTemplate'), + avatarTemplate: u.get('avatar_template'), title: u.get('username') }); iconsHtml += ""; @@ -45,9 +58,18 @@ export default Ember.Component.extend(StringBuffer, { // TODO postUrl might be uninitialized? pick a good default 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'))); - renderActionIf('can_defer_flags', 'defer-flags', I18n.t("post.actions.defer_flags", { count: c.count })); + + if (users.length === 0) { + 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("
"); }); @@ -79,8 +101,12 @@ export default Ember.Component.extend(StringBuffer, { } // User wants to know who actioned it + const usersByType = this.get('usersByType'); 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; } diff --git a/app/assets/javascripts/discourse/components/post-menu.js.es6 b/app/assets/javascripts/discourse/components/post-menu.js.es6 index 9981c5330bc..1cfa0114ba9 100644 --- a/app/assets/javascripts/discourse/components/post-menu.js.es6 +++ b/app/assets/javascripts/discourse/components/post-menu.js.es6 @@ -165,15 +165,12 @@ const PostMenuComponent = Ember.Component.extend(StringBuffer, { }, clickLikeCount() { - const likeAction = this.get('post.likeAction'); - if (likeAction) { - const users = likeAction.get('users'); - if (users && users.length) { - users.clear(); - } else { - likeAction.loadUsers(this.get('post')); - } - } + this.sendActionTarget('toggleWhoLiked'); + }, + + sendActionTarget(action, arg) { + const target = this.get(`${action}Target`); + return target ? target.send(this.get(action), arg) : this.sendAction(action, arg); }, clickReplies() { @@ -268,13 +265,13 @@ const PostMenuComponent = Ember.Component.extend(StringBuffer, { self = this; if (acted) { - this.sendAction('toggleLike', post); + this.sendActionTarget('toggleLike'); $likeButton.removeClass('has-like').addClass('like'); } else { const scale = [1.0, 1.5]; animateHeart($heart, scale[0], scale[1], function() { animateHeart($heart, scale[1], scale[0], function() { - self.sendAction('toggleLike', post); + self.sendActionTarget('toggleLike'); $likeButton.removeClass('like').addClass('has-like'); }); }); diff --git a/app/assets/javascripts/discourse/components/who-liked.js.es6 b/app/assets/javascripts/discourse/components/who-liked.js.es6 index 901c948c55c..a26f468999c 100644 --- a/app/assets/javascripts/discourse/components/who-liked.js.es6 +++ b/app/assets/javascripts/discourse/components/who-liked.js.es6 @@ -1,15 +1,14 @@ import StringBuffer from 'discourse/mixins/string-buffer'; export default Ember.Component.extend(StringBuffer, { - likedUsers: Ember.computed.alias('post.likeAction.users'), - rerenderTriggers: ['likedUsers.length'], + rerenderTriggers: ['users.length'], renderString(buffer) { - const likedUsers = this.get('likedUsers'); - if (likedUsers && likedUsers.length > 0) { + const users = this.get('users'); + if (users && users.length > 0) { buffer.push("
"); let iconsHtml = ""; - likedUsers.forEach(function(u) { + users.forEach(function(u) { iconsHtml += ""; iconsHtml += Discourse.Utilities.avatarImg({ size: 'small', diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 58e468e93f7..725ec0ce73c 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -144,13 +144,6 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { return false; }, - toggleLike(post) { - const likeAction = post.get('likeAction'); - if (likeAction && likeAction.get('canToggle')) { - likeAction.toggle(post); - } - }, - recoverPost(post) { // Recovering the first post recovers the topic instead if (post.get('post_number') === 1) { diff --git a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 index 0172e8167ce..1561d1ab7de 100644 --- a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 +++ b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 @@ -27,7 +27,7 @@ const bindings = { 'home': {handler: 'goToFirstPost', anonymous: true}, 'j': {handler: 'selectDown', 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 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 diff --git a/app/assets/javascripts/discourse/models/action-summary.js.es6 b/app/assets/javascripts/discourse/models/action-summary.js.es6 index 15a6d9bcfaa..621226d2868 100644 --- a/app/assets/javascripts/discourse/models/action-summary.js.es6 +++ b/app/assets/javascripts/discourse/models/action-summary.js.es6 @@ -17,9 +17,6 @@ export default RestModel.extend({ } }.property('count', 'acted', 'actionType'), - usersCollapsed: Em.computed.not('usersExpanded'), - usersExpanded: Em.computed.gt('users.length', 0), - canToggle: function() { return this.get('can_undo') || this.get('can_act'); }.property('can_undo', 'can_act'), @@ -32,17 +29,15 @@ export default RestModel.extend({ can_act: true, can_undo: false }); - - if (this.get('usersExpanded')) { - this.get('users').removeObject(Discourse.User.current()); - } }, toggle: function(post) { if (!this.get('acted')) { this.act(post); + return true; } else { this.undo(post); + return false; } }, @@ -66,14 +61,8 @@ export default RestModel.extend({ 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 const self = this; - return Discourse.ajax("/post_actions", { type: 'POST', data: { @@ -121,16 +110,11 @@ export default RestModel.extend({ }); }, - loadUsers: function(post) { - const self = this; - Discourse.ajax("/post_actions/users", { - data: { - id: post.get('id'), - post_action_type_id: this.get('id') - } + loadUsers(post) { + return Discourse.ajax("/post_actions/users", { + data: { id: post.get('id'), post_action_type_id: this.get('id') } }).then(function (result) { const users = []; - self.set('users', users); result.forEach(function(user) { if (user.id === Discourse.User.currentProp('id')) { users.pushObject(Discourse.User.current()); @@ -138,6 +122,7 @@ export default RestModel.extend({ users.pushObject(Discourse.User.create(user)); } }); + return users; }); } }); diff --git a/app/assets/javascripts/discourse/templates/post.hbs b/app/assets/javascripts/discourse/templates/post.hbs index 70f4c910c3b..c4f9c17bcbc 100644 --- a/app/assets/javascripts/discourse/templates/post.hbs +++ b/app/assets/javascripts/discourse/templates/post.hbs @@ -104,16 +104,19 @@ recoverPost="recoverPost" deletePost="deletePost" toggleLike="toggleLike" + toggleLikeTarget=view showFlags="showFlags" editPost="editPost" toggleBookmark="toggleBookmark" toggleWiki="toggleWiki" togglePostType="togglePostType" rebakePost="rebakePost" - unhidePost="unhidePost"}} + unhidePost="unhidePost" + toggleWhoLiked="toggleWhoLiked" + toggleWhoLikedTarget=view}}
- {{who-liked post=this}} + {{who-liked users=view.likedUsers}} {{#if replies}}
{{#each reply in replies}} diff --git a/app/assets/javascripts/discourse/views/post-menu.js.es6 b/app/assets/javascripts/discourse/views/post-menu.js.es6 deleted file mode 100644 index e33b553a266..00000000000 --- a/app/assets/javascripts/discourse/views/post-menu.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -import PostMenuComponent from 'discourse/components/post-menu'; - -Ember.warn("PostMenuView has been deprecated, use PostMenuComponent instead"); - -export default PostMenuComponent.extend(); diff --git a/app/assets/javascripts/discourse/views/post.js.es6 b/app/assets/javascripts/discourse/views/post.js.es6 index d8ea6559a9c..cceef1e3ce6 100644 --- a/app/assets/javascripts/discourse/views/post.js.es6 +++ b/app/assets/javascripts/discourse/views/post.js.es6 @@ -1,7 +1,7 @@ import ScreenTrack from 'discourse/lib/screen-track'; import { number } from 'discourse/lib/formatter'; 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'; const DAY = 60 * 50 * 1000; @@ -18,8 +18,13 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, { 'whisper'], post: Ember.computed.alias('content'), - postElementId: fmt('post.post_number', 'post_%@'), + likedUsers: null, + + @on('init') + initLikedUsers() { + this.set('likedUsers', []); + }, @computed('post.post_type') whisper(postType) { @@ -197,6 +202,33 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, { }, 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 toggleReplyHistory(post) { const replyHistory = post.get('replyHistory'),