Skip to content

Commit

Permalink
* cleanup people_controller#show, add people_controller#stream for json
Browse files Browse the repository at this point in the history
* introduce new presenters and extend the functionality of the BasePresenter
* add a handlebars template for the profile sidebar, render it everytime we need to update
* introduce a 'aspect_membership:update' global event
  • Loading branch information
Raven24 committed Sep 5, 2014
1 parent edaede8 commit 9b3056d
Show file tree
Hide file tree
Showing 19 changed files with 332 additions and 99 deletions.
27 changes: 23 additions & 4 deletions app/assets/javascripts/app/helpers/handlebars-helpers.js
Expand Up @@ -7,6 +7,7 @@ Handlebars.registerHelper('imageUrl', function(path){
});

Handlebars.registerHelper('linkToPerson', function(context, block) {
if( !context ) context = this;
var html = "<a href=\"/people/" + context.guid + "\" class=\"author-name ";
html += Handlebars.helpers.hovercardable(context);
html += "\">";
Expand All @@ -16,6 +17,22 @@ Handlebars.registerHelper('linkToPerson', function(context, block) {
return html
});

// relationship indicator for profile page
Handlebars.registerHelper('sharingBadge', function(person) {
var i18n_scope = 'people.helper.is_not_sharing';
var icon = 'icons-circle';
if( person.is_sharing ) {
i18n_scope = 'people.helper.is_sharing';
icon = 'icons-check_yes_ok';
}

var title = Diaspora.I18n.t(i18n_scope, {name: person.name});
var html = '<div class="sharing_message_container" title="'+title+'" data-placement="bottom">'+
' <div id="sharing_message" class="'+icon+'"></div>'+
'</div>';
return html;
});


// allow hovercards for users that are not the current user.
// returns the html class name used to trigger hovercards.
Expand All @@ -29,15 +46,17 @@ Handlebars.registerHelper('hovercardable', function(person) {
Handlebars.registerHelper('personImage', function(person, size, imageClass) {
/* we return here if person.avatar is blank, because this happens when a
* user is unauthenticated. we don't know why this happens... */
if( _.isUndefined(person.avatar) ) { return }
var avatar = person.avatar || person.profile.avatar;
if( !avatar ) return;

var name = ( person.name ) ? person.name : 'avatar';
size = ( !_.isString(size) ) ? "small" : size;
imageClass = ( !_.isString(imageClass) ) ? size : imageClass;

return _.template('<img src="<%= src %>" class="avatar <%= img_class %>" title="<%= title %>" />', {
'src': person.avatar[size],
return _.template('<img src="<%= src %>" class="avatar <%= img_class %>" title="<%= title %>" alt="<%= title %>" />', {
'src': avatar[size],
'img_class': imageClass,
'title': _.escape(person.name)
'title': _.escape(name)
});
});

Expand Down
39 changes: 39 additions & 0 deletions app/assets/javascripts/app/models/person.js
@@ -0,0 +1,39 @@
app.models.Person = Backbone.Model.extend({
urlRoot: '/people',

url: function() {
return this.urlRoot + '/' + this.get('guid');
},

initialize: function() {
if( this.get('profile') )
this.profile = new app.models.Profile(this.get('profile'));
},

isSharing: function() {
var rel = this.get('relationship');
return (rel == 'mutual' || rel == 'sharing');
},

isReceiving: function() {
var rel = this.get('relationship');
return (rel == 'mutual' || rel == 'receiving');
},

isMutual: function() {
return (this.get('relationship') == 'mutual');
},

isBlocked: function() {
return (this.get('relationship') == 'blocked');
},

block: function() {
var self = this;
var block = new app.models.Block({block: {person_id: this.id}});

// return the jqXHR with Promise interface
return block.save()
.done(function() { app.events.trigger('person:block:'+self.id); });
}
});
49 changes: 26 additions & 23 deletions app/assets/javascripts/app/pages/profile.js
@@ -1,44 +1,47 @@

// TODO: this view should be model-driven an re-render when it was updated,
// instead of changing classes/attributes on elements.
app.pages.Profile = Backbone.View.extend({
// TODO: update the aspect_membership dropdown, too, every time we render the view...
app.pages.Profile = app.views.Base.extend({
events: {
'click #block_user_button': 'blockPerson'
},

subviews: {
'#profile .badge': 'sidebarView'
},

tooltipSelector: '.profile_button div, .sharing_message_container',

initialize: function(opts) {
// cache element references
this.el_profile_btns = this.$('#profile_buttons');
this.el_sharing_msg = this.$('#sharing_message');
if( app.hasPreload('person') )
this.model = new app.models.Person(app.parsePreload('person'));

// init tooltips
this.el_profile_btns.find('.profile_button div, .sharin_message_container')
.tooltip({placement: 'bottom'});
this.model.on('change', this.render, this);

// respond to global events
var person_id = this.$('#profile .avatar:first').data('person_id');
app.events.on('person:block:'+person_id, this._markBlocked, this);
// bind to global events
var id = this.model.get('id');
app.events.on('person:block:'+id, this.reload, this);
app.events.on('aspect_membership:update', this.reload, this);
},

sidebarView: function() {
return new app.views.ProfileSidebar({model: this.model});
},

blockPerson: function(evt) {
if( !confirm(Diaspora.I18n.t('ignore_user')) ) return;

var person_id = $(evt.target).data('person-id');
var block = new app.models.Block({block: {person_id: person_id}});
block.save()
.done(function() { app.events.trigger('person:block:'+person_id); })
.fail(function() { Diaspora.page.flashMessages.render({
var block = this.model.block();
block.fail(function() {
Diaspora.page.flashMessages.render({
success: false,
notice: Diaspora.I18n.t('ignore_failed')
}); });
});
});

return false;
},

_markBlocked: function() {
this.el_profile_btns.attr('class', 'blocked');
this.el_sharing_msg.attr('class', 'icons-circle');

this.el_profile_btns.find('.profile_button, .white_bar').remove();
reload: function() {
this.model.fetch();
}
});
3 changes: 2 additions & 1 deletion app/assets/javascripts/app/router.js
Expand Up @@ -54,10 +54,11 @@ app.Router = Backbone.Router.extend({
renderPage : function(pageConstructor){
app.page && app.page.unbind && app.page.unbind(); //old page might mutate global events $(document).keypress, so unbind before creating
app.page = pageConstructor(); //create new page after the world is clean (like that will ever happen)
app.page.render();

if( !$.contains(document, app.page.el) ) {
// view element isn't already attached to the DOM, insert it
$("#container").empty().append(app.page.render().el);
$("#container").empty().append(app.page.el);
}
},

Expand Down
1 change: 1 addition & 0 deletions app/assets/javascripts/app/views.js
Expand Up @@ -38,6 +38,7 @@ app.views.Base = Backbone.View.extend({
this.template = HandlebarsTemplates[this.templateName+"_tpl"]
if(!this.template) {
console.log(this.templateName ? ("no template for " + this.templateName) : "no templateName specified")
return;
}

this.$el
Expand Down
Expand Up @@ -23,20 +23,26 @@ app.views.AspectMembershipBlueprint = Backbone.View.extend({
// -> addMembership
// -> removeMembership
_clickHandler: function(evt) {
var promise = null;
this.list_item = $(evt.target);
this.dropdown = this.list_item.parent();

this.list_item.addClass('loading');

if( this.list_item.is('.selected') ) {
var membership_id = this.list_item.data('membership_id');
this.removeMembership(membership_id);
promise = this.removeMembership(membership_id);
} else {
var aspect_id = this.list_item.data('aspect_id');
var person_id = this.dropdown.data('person_id');
this.addMembership(person_id, aspect_id);
promise = this.addMembership(person_id, aspect_id);
}

promise && promise.always(function() {
// trigger a global event
app.events.trigger('aspect_membership:update');
});

return false; // stop the event
},

Expand All @@ -57,7 +63,7 @@ app.views.AspectMembershipBlueprint = Backbone.View.extend({
this._displayError('aspect_dropdown.error');
}, this);

aspect_membership.save();
return aspect_membership.save();
},

_successSaveCb: function(aspect_membership) {
Expand Down Expand Up @@ -100,7 +106,7 @@ app.views.AspectMembershipBlueprint = Backbone.View.extend({
this._displayError('aspect_dropdown.error_remove');
}, this);

aspect_membership.destroy();
return aspect_membership.destroy();
},

_successDestroyCb: function(aspect_membership) {
Expand Down
14 changes: 10 additions & 4 deletions app/assets/javascripts/app/views/aspect_membership_view.js
Expand Up @@ -23,20 +23,26 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
// -> addMembership
// -> removeMembership
_clickHandler: function(evt) {
var promise = null;
this.list_item = $(evt.target).closest('li.aspect_selector');
this.dropdown = this.list_item.parent();

this.list_item.addClass('loading');

if( this.list_item.is('.selected') ) {
var membership_id = this.list_item.data('membership_id');
this.removeMembership(membership_id);
promise = this.removeMembership(membership_id);
} else {
var aspect_id = this.list_item.data('aspect_id');
var person_id = this.dropdown.data('person_id');
this.addMembership(person_id, aspect_id);
promise = this.addMembership(person_id, aspect_id);
}

promise && promise.always(function() {
// trigger a global event
app.events.trigger('aspect_membership:update');
});

return false; // stop the event
},

Expand All @@ -57,7 +63,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
this._displayError('aspect_dropdown.error');
}, this);

aspect_membership.save();
return aspect_membership.save();
},

_successSaveCb: function(aspect_membership) {
Expand Down Expand Up @@ -99,7 +105,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
this._displayError('aspect_dropdown.error_remove');
}, this);

aspect_membership.destroy();
return aspect_membership.destroy();
},

_successDestroyCb: function(aspect_membership) {
Expand Down
18 changes: 18 additions & 0 deletions app/assets/javascripts/app/views/profile_sidebar_view.js
@@ -0,0 +1,18 @@

app.views.ProfileSidebar = app.views.Base.extend({
templateName: 'profile_sidebar',

presenter: function() {
return _.extend({}, this.defaultPresenter(), {
do_profile_btns: this._shouldDoProfileBtns(),
is_sharing: this.model.isSharing(),
is_receiving: this.model.isReceiving(),
is_mutual: this.model.isMutual(),
is_not_blocked: !this.model.isBlocked()
});
},

_shouldDoProfileBtns: function() {
return (app.currentUser.authenticated() && !this.model.get('is_own_profile'));
},
});
10 changes: 5 additions & 5 deletions app/assets/stylesheets/profile.css.scss
Expand Up @@ -44,7 +44,7 @@
width: 50px;
}
}
.only_sharing {
.sharing {
background-color: rgb(142, 222, 61);
.profile_button {
width: 150px;
Expand Down Expand Up @@ -77,21 +77,21 @@
background-color: white;
@include border-bottom-left-radius(8px);
}

.profile_button {
display: inline-block;
text-align: center;
}

a { @include opacity(0.5); }
a:hover { @include opacity(1); }
.icons-check_yes_ok {

.icons-check_yes_ok {
display: inline-block;
height: 18px;
width: 18px;
}
.icons-circle {
.icons-circle {
display: inline-block;
height: 18px;
width: 18px;
Expand Down
36 changes: 36 additions & 0 deletions app/assets/templates/profile_sidebar_tpl.jst.hbs
@@ -0,0 +1,36 @@

<div class="profile_photo">
{{#linkToPerson this}}
{{{personImage this "l"}}}
{{/linkToPerson}}
</div>

{{#if do_profile_btns}}
<div id="profile_buttons" class="{{relationship}}">
{{{sharingBadge this}}}

{{#if is_receiving}}
<div class="profile_button">
<a href="" rel="facebox">
<div id="mention_button" class="icons-mention" title="{{t 'people.mention'}}" data-placement="bottom"></div>
</a>
</div>
{{/if}}

{{#if is_mutual}}
<div class="profile_button">
<a href="" rel="facebox">
<div id="message_button" class="icons-message" title="{{t 'people.message'}}" data-placement="bottom"></div>
</a>
</div>
{{/if}}

{{#if is_not_blocked}}
<div class="profile_button">
<a href="#" rel="nofollow">
<div id="block_user_button" class="icons-ignoreuser block_user" title="{{t 'ignore'}}" data-placement="bottom"></div>
</a>
</div>
{{/if}}
</div>
{{/if}}

0 comments on commit 9b3056d

Please sign in to comment.