mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 17:46:05 -05:00
Pop up with user information when clicking avatar on topic page
This commit is contained in:
parent
578ef2098b
commit
fc00269b7f
13 changed files with 198 additions and 20 deletions
|
@ -105,19 +105,20 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
|||
$('#main').on('click.discourse', 'a', function(e) {
|
||||
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey) { return; }
|
||||
|
||||
var $currentTarget = $(e.currentTarget);
|
||||
var href = $currentTarget.attr('href');
|
||||
if (!href) { return; }
|
||||
if (href === '#') { return; }
|
||||
if ($currentTarget.attr('target')) { return; }
|
||||
if ($currentTarget.data('auto-route')) { return; }
|
||||
var $currentTarget = $(e.currentTarget),
|
||||
href = $currentTarget.attr('href');
|
||||
|
||||
// If it's an ember #link-to skip it
|
||||
if ($currentTarget.hasClass('ember-view')) { return; }
|
||||
|
||||
if ($currentTarget.hasClass('lightbox')) { return; }
|
||||
if (href.indexOf("mailto:") === 0) { return; }
|
||||
if (href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i"))) { return; }
|
||||
if (!href ||
|
||||
href === '#' ||
|
||||
$currentTarget.attr('target') ||
|
||||
$currentTarget.data('ember-action') ||
|
||||
$currentTarget.data('auto-route') ||
|
||||
$currentTarget.hasClass('ember-view') ||
|
||||
$currentTarget.hasClass('lightbox') ||
|
||||
href.indexOf("mailto:") === 0 ||
|
||||
(href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i")))) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
Discourse.URL.routeTo(href);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
A controller for expanding information about a poster.
|
||||
|
||||
@class PosterExpansion
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.PosterExpansionController = Discourse.ObjectController.extend({
|
||||
needs: ['topic'],
|
||||
|
||||
show: function(user, post) {
|
||||
this.setProperties({model: user, post: post});
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.set('model', null);
|
||||
},
|
||||
|
||||
actions: {
|
||||
togglePosts: function(user) {
|
||||
var postStream = this.get('controllers.topic.postStream');
|
||||
postStream.toggleParticipant(user.get('username'));
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -133,7 +133,6 @@ Discourse.PostStream = Em.Object.extend({
|
|||
|
||||
hasNoFilters: Em.computed.empty('filterDesc'),
|
||||
|
||||
|
||||
/**
|
||||
Returns the window of posts above the current set in the stream, bound to the top of the stream.
|
||||
This is the collection we'll ask for when scrolling upwards.
|
||||
|
|
|
@ -259,7 +259,6 @@ Discourse.User = Discourse.Model.extend({
|
|||
json.user.invited_by = Discourse.User.create(json.user.invited_by);
|
||||
}
|
||||
|
||||
|
||||
user.setProperties(json.user);
|
||||
return user;
|
||||
});
|
||||
|
@ -297,6 +296,17 @@ Discourse.User = Discourse.Model.extend({
|
|||
Discourse.User.reopenClass(Discourse.Singleton, {
|
||||
|
||||
|
||||
/**
|
||||
Find a `Discourse.User` for a given username.
|
||||
|
||||
@method findByUsername
|
||||
@returns {Promise} a promise that resolves to a `Discourse.User`
|
||||
**/
|
||||
findByUsername: function(username) {
|
||||
var user = Discourse.User.create({username: username});
|
||||
return user.findDetails();
|
||||
},
|
||||
|
||||
/**
|
||||
The current singleton will retrieve its attributes from the `PreloadStore`
|
||||
if it exists. Otherwise, no instance is created.
|
||||
|
@ -325,7 +335,6 @@ Discourse.User.reopenClass(Discourse.Singleton, {
|
|||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
Checks if given username is valid for this email address
|
||||
|
||||
|
|
|
@ -13,6 +13,14 @@ Discourse.TopicRoute = Discourse.Route.extend({
|
|||
actions: {
|
||||
// Modals that can pop up within a topic
|
||||
|
||||
showPosterExpansion: function(post) {
|
||||
var self = this;
|
||||
|
||||
Discourse.User.findByUsername(post.get('username')).then(function (user) {
|
||||
self.controllerFor('posterExpansion').show(user, post);
|
||||
});
|
||||
},
|
||||
|
||||
showFlags: function(post) {
|
||||
Discourse.Route.showModal(this, 'flag', post);
|
||||
this.controllerFor('flag').setProperties({ selected: null });
|
||||
|
@ -80,9 +88,10 @@ Discourse.TopicRoute = Discourse.Route.extend({
|
|||
|
||||
// Clear the search context
|
||||
this.controllerFor('search').set('searchContext', null);
|
||||
this.controllerFor('posterExpansion').set('model', null);
|
||||
|
||||
var topicController = this.controllerFor('topic');
|
||||
var postStream = topicController.get('postStream');
|
||||
var topicController = this.controllerFor('topic'),
|
||||
postStream = topicController.get('postStream');
|
||||
postStream.cancelFilter();
|
||||
|
||||
topicController.set('multiSelect', false);
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
<div class='topic-meta-data span2'>
|
||||
{{#unless userDeleted}}
|
||||
<div {{bindAttr class=":contents byTopicCreator:topic-creator"}}>
|
||||
<a href='{{unbound usernameUrl}}'>{{avatar this imageSize="large"}}</a>
|
||||
<h3 {{bindAttr class="staff new_user"}}><a href='{{unbound usernameUrl}}'>{{breakUp username}}</a></h3>
|
||||
{{#if user_title}}<div class="user-title">{{user_title}}</div>{{/if}}
|
||||
<a href='{{unbound usernameUrl}}' {{action showPosterExpansion this}}>{{avatar this imageSize="large"}}</a>
|
||||
<h3 {{bindAttr class="staff new_user"}}><a href='{{unbound usernameUrl}}' {{action showPosterExpansion this}}>{{breakUp username}}</a></h3>
|
||||
{{#if user_title}}<div class="user-title" {{action showPosterExpansion this}}>{{user_title}}</div>{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="contents">
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{{#if model}}
|
||||
{{avatar model imageSize="huge"}}
|
||||
|
||||
<h1>{{username}}</h1>
|
||||
<h2>{{name}}</h2>
|
||||
<h3>{{i18n last_post}}: {{unboundDate last_posted_at}}</h3>
|
||||
|
||||
<div class='bottom'>
|
||||
{{#if bio_cooked}}<div class='bio'>{{{bio_cooked}}}</div>{{/if}}
|
||||
|
||||
<button class='btn'><i class='icon icon-envelope'></i>{{i18n user.private_message}}</button>
|
||||
|
||||
{{#link-to 'user' model class="btn"}}<i class='icon icon-user'></i>{{i18n user.profile}}{{/link-to}}
|
||||
|
||||
<button class='btn' {{action togglePosts this}}><i class='icon icon-filter'></i>{{i18n topic.filter_to username="username"}}</button>
|
||||
</div>
|
||||
|
||||
{{/if}}
|
|
@ -125,6 +125,8 @@
|
|||
</div>
|
||||
|
||||
{{render share}}
|
||||
{{render posterExpansion}}
|
||||
|
||||
{{#if currentUser.enable_quoting}}
|
||||
{{render quoteButton}}
|
||||
{{/if}}
|
||||
|
@ -132,3 +134,4 @@
|
|||
{{#if currentUser.staff}}
|
||||
{{render topicAdminMenu content}}
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
Shows expanded details for a poster
|
||||
|
||||
@class PosterExpansionView
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.PosterExpansionView = Discourse.View.extend({
|
||||
elementId: 'poster-expansion',
|
||||
classNameBindings: ['controller.model::hidden'],
|
||||
|
||||
// Position the expansion when the model changes
|
||||
_modelChanged: function() {
|
||||
var post = this.get('controller.post'),
|
||||
self = this;
|
||||
|
||||
Em.run.schedule('afterRender', function() {
|
||||
if (post) {
|
||||
var $post = $('#' + post.get('postElementId')),
|
||||
$avatar = $('.topic-meta-data img.avatar', $post),
|
||||
position = $avatar.offset();
|
||||
|
||||
position.left += $avatar.width() + 5;
|
||||
self.$().css(position);
|
||||
}
|
||||
});
|
||||
|
||||
}.observes('controller.model'),
|
||||
|
||||
didInsertElement: function() {
|
||||
var self = this;
|
||||
$('html').on('mousedown.outside-poster-expansion', function(e) {
|
||||
if (self.$().has(e.target).length !== 0) { return; }
|
||||
self.get('controller').set('model', null);
|
||||
return true;
|
||||
});
|
||||
},
|
||||
|
||||
willDestroyElement: function() {
|
||||
$('html').off('mousedown.outside-poster-expansion');
|
||||
}
|
||||
|
||||
});
|
51
app/assets/stylesheets/desktop/poster_expansion.scss
Normal file
51
app/assets/stylesheets/desktop/poster_expansion.scss
Normal file
|
@ -0,0 +1,51 @@
|
|||
// styles that apply to the "share" popup when sharing a link to a post or topic
|
||||
|
||||
@import "common/foundation/variables";
|
||||
@import "common/foundation/mixins";
|
||||
|
||||
#poster-expansion {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
z-index: 990;
|
||||
@include border-radius-all(3px);
|
||||
@include box-shadow(1px 1px 5px $darkish_gray);
|
||||
background-color: $white;
|
||||
padding: 7px 7px 6px 7px;
|
||||
width: 400px;
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
line-height: 33px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
line-height: 22px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
clear: both;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
float: left;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0 0 7px 0;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,8 @@ class TopicsController < ApplicationController
|
|||
|
||||
opts = params.slice(:username_filters, :filter, :page, :post_number)
|
||||
|
||||
opts[:username_filters] = [opts[:username_filters]] if opts[:username_filters].is_a?(String)
|
||||
|
||||
begin
|
||||
@topic_view = TopicView.new(params[:id] || params[:topic_id], current_user, opts)
|
||||
rescue Discourse::NotFound
|
||||
|
|
|
@ -581,6 +581,7 @@ en:
|
|||
title: Topic Rank Details
|
||||
|
||||
topic:
|
||||
filter_to: "Toggle only posts by {{username}} in this topic"
|
||||
create_in: 'Create {{categoryName}} Topic'
|
||||
create: 'Create Topic'
|
||||
create_long: 'Create a new Topic'
|
||||
|
|
|
@ -25,3 +25,15 @@ test("isAllowedToUploadAFile", function() {
|
|||
user.setProperties({ admin: false, moderator: true });
|
||||
ok(user.isAllowedToUploadAFile("image"), "moderator can always upload a file");
|
||||
});
|
||||
|
||||
|
||||
asyncTestDiscourse("findByUsername", function() {
|
||||
expect(3);
|
||||
|
||||
Discourse.User.findByUsername('eviltrout').then(function (user) {
|
||||
present(user);
|
||||
equal(user.get('username'), 'eviltrout', 'it has the correct username');
|
||||
equal(user.get('name'), 'Robin Ward', 'it has the full name since it has details');
|
||||
start();
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue