From 27f786e06a4dc7dfcfc7938be3bdefac1f059ff3 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 23 Jul 2014 16:10:01 -0400 Subject: [PATCH] FEATURE: Show user popup when clicking on an @mention in a post. --- .../discourse/components/poster-name.js.es6 | 2 - .../controllers/poster-expansion.js.es6 | 22 +++--- .../discourse/helpers/application_helpers.js | 2 +- .../discourse/routes/topic_route.js | 11 ++- .../templates/embedded_post.js.handlebars | 4 +- .../discourse/templates/post.js.handlebars | 4 +- .../templates/poster_expansion.handlebars | 14 ++-- .../javascripts/discourse/views/post_view.js | 71 ++++++++++--------- .../discourse/views/poster-expansion.js.es6 | 12 +++- 9 files changed, 83 insertions(+), 59 deletions(-) diff --git a/app/assets/javascripts/discourse/components/poster-name.js.es6 b/app/assets/javascripts/discourse/components/poster-name.js.es6 index 284376d3ba0..3817b2d33d6 100644 --- a/app/assets/javascripts/discourse/components/poster-name.js.es6 +++ b/app/assets/javascripts/discourse/components/poster-name.js.es6 @@ -34,8 +34,6 @@ var PosterNameComponent = Em.Component.extend({ } buffer.push(""); - - // Are we showing full names? if (name && this.get('displayNameOnPosts') && (this.sanitizeName(name) !== this.sanitizeName(username))) { name = Handlebars.Utils.escapeExpression(name); diff --git a/app/assets/javascripts/discourse/controllers/poster-expansion.js.es6 b/app/assets/javascripts/discourse/controllers/poster-expansion.js.es6 index a0ec468b1ae..5130d1a9b82 100644 --- a/app/assets/javascripts/discourse/controllers/poster-expansion.js.es6 +++ b/app/assets/javascripts/discourse/controllers/poster-expansion.js.es6 @@ -2,7 +2,9 @@ export default Discourse.ObjectController.extend({ needs: ['topic'], visible: false, user: null, + username: null, participant: null, + avatar: null, postStream: Em.computed.alias('controllers.topic.postStream'), enoughPostsForFiltering: Em.computed.gte('participant.post_count', 2), @@ -20,22 +22,25 @@ export default Discourse.ObjectController.extend({ showMoreBadges: Em.computed.gt('moreBadgesCount', 0), - show: function(post) { + show: function(username, uploadedAvatarId) { + var url = "/users/" + username; // Don't show on mobile if (Discourse.Mobile.mobileView) { - Discourse.URL.routeTo(post.get('usernameUrl')); + Discourse.URL.routeTo(url); return; } - var currentPostId = this.get('id'), + var currentUsername = this.get('username'), wasVisible = this.get('visible'); - this.setProperties({model: post, visible: true}); + this.set('avatar', {username: username, uploaded_avatar_id: uploadedAvatarId}); + + this.setProperties({visible: true, username: username}); // If we click the avatar again, close it. - if (post.get('id') === currentPostId && wasVisible) { - this.setProperties({ visible: false, model: null }); + if (username === currentUsername && wasVisible) { + this.setProperties({ visible: false, username: null, avatar: null }); return; } @@ -44,13 +49,14 @@ export default Discourse.ObjectController.extend({ // Retrieve their participants info var participants = this.get('topic.details.participants'); if (participants) { - this.set('participant', participants.findBy('username', post.get('username'))); + this.set('participant', participants.findBy('username', username)); } var self = this; self.set('user', null); - Discourse.User.findByUsername(post.get('username')).then(function (user) { + Discourse.User.findByUsername(username).then(function (user) { self.set('user', user); + self.set('avatar', user); }); }, diff --git a/app/assets/javascripts/discourse/helpers/application_helpers.js b/app/assets/javascripts/discourse/helpers/application_helpers.js index 46035e1f3f5..43b2a7045f2 100644 --- a/app/assets/javascripts/discourse/helpers/application_helpers.js +++ b/app/assets/javascripts/discourse/helpers/application_helpers.js @@ -189,7 +189,7 @@ Handlebars.registerHelper('avatar', function(user, options) { @for Handlebars **/ Em.Handlebars.helper('bound-avatar', function(user, size, uploadId) { - + if (Em.isEmpty(user)) { return; } var username = Em.get(user, 'username'); if(arguments.length < 4){ diff --git a/app/assets/javascripts/discourse/routes/topic_route.js b/app/assets/javascripts/discourse/routes/topic_route.js index e5c57f056b9..48a0938e535 100644 --- a/app/assets/javascripts/discourse/routes/topic_route.js +++ b/app/assets/javascripts/discourse/routes/topic_route.js @@ -14,8 +14,15 @@ Discourse.TopicRoute = Discourse.Route.extend({ actions: { // Modals that can pop up within a topic - showPosterExpansion: function(post) { - this.controllerFor('poster-expansion').show(post); + expandPostUser: function(post) { + this.controllerFor('poster-expansion').show(post.get('username'), post.get('uploaded_avatar_id')); + }, + + expandPostUsername: function(username) { + username = username.replace(/^@/, ''); + if (!Em.isEmpty(username)) { + this.controllerFor('poster-expansion').show(username); + } }, composePrivateMessage: function(user) { diff --git a/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars b/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars index a2007af2106..acc40ed72bc 100644 --- a/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars +++ b/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars @@ -2,13 +2,13 @@
- {{poster-avatar action="showPosterExpansion" post=this classNames="main-avatar"}} + {{poster-avatar action="expandPostUser" post=this classNames="main-avatar"}}
diff --git a/app/assets/javascripts/discourse/templates/post.js.handlebars b/app/assets/javascripts/discourse/templates/post.js.handlebars index 4f04e717036..7202624bbac 100644 --- a/app/assets/javascripts/discourse/templates/post.js.handlebars +++ b/app/assets/javascripts/discourse/templates/post.js.handlebars @@ -20,7 +20,7 @@
{{#unless userDeleted}}
- {{poster-avatar action="showPosterExpansion" post=this classNames="main-avatar"}} + {{poster-avatar action="expandPostUser" post=this classNames="main-avatar"}}
{{else}}
@@ -34,7 +34,7 @@
{{/if}} + {{#if user}} -
{{#if user.bio_cooked}}
{{{user.bio_cooked}}}
{{/if}} diff --git a/app/assets/javascripts/discourse/views/post_view.js b/app/assets/javascripts/discourse/views/post_view.js index 38419310ae1..31638e39707 100644 --- a/app/assets/javascripts/discourse/views/post_view.js +++ b/app/assets/javascripts/discourse/views/post_view.js @@ -1,11 +1,3 @@ -/** - This view renders a post. - - @class PostView - @extends Discourse.GroupedView - @namespace Discourse - @module Discourse -**/ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { classNames: ['topic-post', 'clearfix'], templateName: 'post', @@ -36,7 +28,7 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { // If the cooked content changed, add the quote controls cookedChanged: function() { - Em.run.scheduleOnce('afterRender', this, 'insertQuoteControls'); + Em.run.scheduleOnce('afterRender', this, '_insertQuoteControls'); }.observes('post.cooked'), mouseUp: function(e) { @@ -66,7 +58,7 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { repliesShown: Em.computed.gt('post.replies.length', 0), - updateQuoteElements: function($aside, desc) { + _updateQuoteElements: function($aside, desc) { var navLink = "", quoteTitle = I18n.t("post.follow_quote"), postNumber = $aside.data('post'); @@ -100,42 +92,39 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { $('.quote-controls', $aside).html(expandContract + navLink); }, - toggleQuote: function($aside) { - $aside.data('expanded',!$aside.data('expanded')); + _toggleQuote: function($aside) { + $aside.data('expanded', !$aside.data('expanded')); if ($aside.data('expanded')) { - this.updateQuoteElements($aside, 'chevron-up'); + this._updateQuoteElements($aside, 'chevron-up'); // Show expanded quote var $blockQuote = $('blockquote', $aside); $aside.data('original-contents',$blockQuote.html()); var originalText = $blockQuote.text().trim(); $blockQuote.html(I18n.t("loading")); - var topic_id = this.get('post.topic_id'); + var topicId = this.get('post.topic_id'); if ($aside.data('topic')) { - topic_id = $aside.data('topic'); + topicId = $aside.data('topic'); } - var post_id = $aside.data('post'); + var postId = parseInt($aside.data('post'), 10); + topicId = parseInt(topicId, 10); - topic_id = parseInt(topic_id,10); - post_id = parseInt(post_id,10); - - Discourse.ajax("/posts/by_number/" + topic_id + "/" + post_id).then(function (result) { + Discourse.ajax("/posts/by_number/" + topicId + "/" + postId).then(function (result) { var parsed = $(result.cooked); parsed.replaceText(originalText, "" + originalText + ""); $blockQuote.showHtml(parsed); }); } else { // Hide expanded quote - this.updateQuoteElements($aside, 'chevron-down'); + this._updateQuoteElements($aside, 'chevron-down'); $('blockquote', $aside).showHtml($aside.data('original-contents')); } return false; }, // Show how many times links have been clicked on - showLinkCounts: function() { - + _showLinkCounts: function() { var self = this, link_counts = this.get('post.link_counts'); @@ -194,7 +183,7 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { }, // Add the quote controls to a post - insertQuoteControls: function() { + _insertQuoteControls: function() { var self = this, $quotes = this.$('aside.quote'); @@ -204,14 +193,14 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { $quotes.each(function(i, e) { var $aside = $(e); if ($aside.data('post')) { - self.updateQuoteElements($aside, 'chevron-down'); + self._updateQuoteElements($aside, 'chevron-down'); var $title = $('.title', $aside); // Unless it's a full quote, allow click to expand if (!($aside.data('full') || $title.data('has-quote-controls'))) { $title.on('click', function(e) { if ($(e.target).is('a')) return true; - self.toggleQuote($aside); + self._toggleQuote($aside); }); $title.data('has-quote-controls', true); } @@ -219,16 +208,17 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { }); }, - willDestroyElement: function() { + _destroyedPostView: function() { Discourse.ScreenTrack.current().stopTracking(this.get('elementId')); - }, + this._unbindExpandMentions(); + }.on('willDestroyElement'), - didInsertElement: function() { + _postViewInserted: function() { var $post = this.$(), post = this.get('post'), postNumber = post.get('post_number'); - this.showLinkCounts(); + this._showLinkCounts(); // Track this post Discourse.ScreenTrack.current().track(this.$().prop('id'), postNumber); @@ -245,12 +235,27 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, { this.trigger('postViewInserted', $post); // Find all the quotes - Em.run.scheduleOnce('afterRender', this, 'insertQuoteControls'); + Em.run.scheduleOnce('afterRender', this, '_insertQuoteControls'); - this.applySearchHighlight(); + this._applySearchHighlight(); + this._bindExpandMentions(); + }.on('didInsertElement'), + + _bindExpandMentions: function() { + var self = this; + this.$('.cooked').on('click.discourse-mention', 'a.mention', function(e) { + var $target = $(e.target); + self.appEvents.trigger('poster:expand', $target); + self.get('controller').send('expandPostUsername', $target.text()); + return false; + }); }, - applySearchHighlight: function(){ + _unbindExpandMentions: function() { + this.$('.cooked').off('click.discourse-mention'); + }, + + _applySearchHighlight: function() { var highlight = this.get('controller.searchHighlight'); var cooked = this.$('.cooked'); diff --git a/app/assets/javascripts/discourse/views/poster-expansion.js.es6 b/app/assets/javascripts/discourse/views/poster-expansion.js.es6 index 8998a9ffadb..6bb871ae748 100644 --- a/app/assets/javascripts/discourse/views/poster-expansion.js.es6 +++ b/app/assets/javascripts/discourse/views/poster-expansion.js.es6 @@ -5,14 +5,22 @@ export default Discourse.View.extend({ classNameBindings: ['controller.visible::hidden', 'controller.showBadges'], _setup: function() { - var self = this; + var self = this, + width = this.$().width(); + this.appEvents.on('poster:expand', function(target) { if (!target) { return; } Em.run.schedule('afterRender', function() { if (target) { var position = target.offset(); if (position) { - position.left += target.width() + 5; + position.left += target.width() + 10; + + var overage = ($(window).width() - 50) - (position.left + width); + if (overage < 0) { + position.left += overage; + position.top += target.height() + 5; + } self.$().css(position); } }