Merge pull request #5473 from svbergerem/contacts-backbonejs
Port contacts page to backbonejs
This commit is contained in:
commit
f20020f06b
35 changed files with 751 additions and 394 deletions
|
|
@ -84,6 +84,7 @@ diaspora.yml file**. The existing settings from 0.4.x and before will not work a
|
|||
* Make sure conversations without any visibilities left are deleted [#5478](https://github.com/diaspora/diaspora/pull/5478)
|
||||
* Change tooltip for delete button in conversations view [#5477](https://github.com/diaspora/diaspora/pull/5477)
|
||||
* Replace a modifier-rescue with a specific rescue [#5491](https://github.com/diaspora/diaspora/pull/5491)
|
||||
* Port contacts page to backbone [#5473](https://github.com/diaspora/diaspora/pull/5473)
|
||||
|
||||
## Bug fixes
|
||||
* orca cannot see 'Add Contact' button [#5158](https://github.com/diaspora/diaspora/pull/5158)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.AspectMemberships = Backbone.Collection.extend({
|
||||
model: app.models.AspectMembership
|
||||
})
|
||||
// @license-end
|
||||
21
app/assets/javascripts/app/collections/contacts.js
Normal file
21
app/assets/javascripts/app/collections/contacts.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Contacts = Backbone.Collection.extend({
|
||||
model: app.models.Contact,
|
||||
|
||||
comparator : function(con1, con2) {
|
||||
if( !con1.person || !con2.person ) return 1;
|
||||
|
||||
if(app.aspect) {
|
||||
var inAspect1 = con1.inAspect(app.aspect.get('id'));
|
||||
var inAspect2 = con2.inAspect(app.aspect.get('id'));
|
||||
if( inAspect1 && !inAspect2 ) return -1;
|
||||
if( !inAspect1 && inAspect2 ) return 1;
|
||||
}
|
||||
|
||||
var n1 = con1.person.get('name');
|
||||
var n2 = con2.person.get('name');
|
||||
return n1.localeCompare(n2);
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -21,7 +21,7 @@ Handlebars.registerHelper('urlTo', function(path_helper, id, data){
|
|||
return Routes[path_helper+'_path'](id, data.hash);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('linkToPerson', function(context, block) {
|
||||
Handlebars.registerHelper('linkToAuthor', function(context, block) {
|
||||
if( !context ) context = this;
|
||||
var html = "<a href=\"/people/" + context.guid + "\" class=\"author-name ";
|
||||
html += Handlebars.helpers.hovercardable(context);
|
||||
|
|
@ -32,6 +32,15 @@ Handlebars.registerHelper('linkToPerson', function(context, block) {
|
|||
return html
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('linkToPerson', function(context, block) {
|
||||
if( !context ) context = this;
|
||||
var html = "<a href=\"/people/" + context.guid + "\" class=\"name\">";
|
||||
html += block.fn(context);
|
||||
html += "</a>";
|
||||
|
||||
return html
|
||||
});
|
||||
|
||||
// relationship indicator for profile page
|
||||
Handlebars.registerHelper('sharingMessage', function(person) {
|
||||
var i18n_scope = 'people.helper.is_not_sharing';
|
||||
|
|
@ -107,5 +116,20 @@ Handlebars.registerHelper('isCurrentProfilePage', function(id, diaspora_handle,
|
|||
return Handlebars.helpers.isCurrentPage('person', id, options) ||
|
||||
Handlebars.helpers.isCurrentPage('user_profile', username, options);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('aspectMembershipIndicator', function(contact,in_aspect) {
|
||||
if(!app.aspect || !app.aspect.get('id')) return '<div class="aspect_membership_dropdown placeholder"></div>';
|
||||
|
||||
var html = '<i class="entypo ';
|
||||
if( in_aspect == 'in_aspect' ) {
|
||||
html += 'circled-cross contact_remove-from-aspect" ';
|
||||
html += 'title="' + Diaspora.I18n.t('contacts.remove_contact') + '" ';
|
||||
} else {
|
||||
html += 'circled-plus contact_add-to-aspect" ';
|
||||
html += 'title="' + Diaspora.I18n.t('contacts.add_contact') + '" ';
|
||||
}
|
||||
html += '></i>';
|
||||
return html;
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
13
app/assets/javascripts/app/models/contact.js
Normal file
13
app/assets/javascripts/app/models/contact.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Contact = Backbone.Model.extend({
|
||||
initialize : function() {
|
||||
this.aspect_memberships = new app.collections.AspectMemberships(this.get('aspect_memberships'));
|
||||
if( this.get('person') ) this.person = new app.models.Person(this.get('person'));
|
||||
},
|
||||
|
||||
inAspect : function(id) {
|
||||
return this.aspect_memberships.any(function(membership){ return membership.get('aspect').id == id; });
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Contacts = Backbone.View.extend({
|
||||
app.pages.Contacts = Backbone.View.extend({
|
||||
|
||||
el: "#contacts_container",
|
||||
|
||||
|
|
@ -8,17 +8,15 @@ app.views.Contacts = Backbone.View.extend({
|
|||
"click #contacts_visibility_toggle" : "toggleContactVisibility",
|
||||
"click #chat_privilege_toggle" : "toggleChatPrivilege",
|
||||
"click #change_aspect_name" : "showAspectNameForm",
|
||||
"click .contact_remove-from-aspect" : "removeContactFromAspect",
|
||||
"click .contact_add-to-aspect" : "addContactToAspect",
|
||||
"keyup #contact_list_search" : "searchContactList"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
initialize: function(opts) {
|
||||
this.visibility_toggle = $("#contacts_visibility_toggle .entypo");
|
||||
this.chat_toggle = $("#chat_privilege_toggle .entypo");
|
||||
this.stream = opts.stream;
|
||||
this.stream.render();
|
||||
$("#people_stream.contacts .header .entypo").tooltip({ 'placement': 'bottom'});
|
||||
$(".contact_remove-from-aspect").tooltip();
|
||||
$(".contact_add-to-aspect").tooltip();
|
||||
$(document).on('ajax:success', 'form.edit_aspect', this.updateAspectName);
|
||||
},
|
||||
|
||||
|
|
@ -69,65 +67,8 @@ app.views.Contacts = Backbone.View.extend({
|
|||
$(".header > h3").show();
|
||||
},
|
||||
|
||||
addContactToAspect: function(e){
|
||||
var contact = $(e.currentTarget);
|
||||
var aspect_membership = new app.models.AspectMembership({
|
||||
'person_id': contact.attr('data-person_id'),
|
||||
'aspect_id': contact.attr('data-aspect_id')
|
||||
});
|
||||
|
||||
aspect_membership.save({},{
|
||||
success: function(model,response){
|
||||
contact.attr('data-membership_id',model.id)
|
||||
.tooltip('destroy')
|
||||
.removeAttr('data-original-title')
|
||||
.removeClass("contact_add-to-aspect").removeClass("circled-plus")
|
||||
.addClass("contact_remove-from-aspect").addClass("circled-cross")
|
||||
.attr('title', Diaspora.I18n.t('contacts.remove_contact'))
|
||||
.tooltip()
|
||||
.closest('.stream_element').addClass('in_aspect');
|
||||
},
|
||||
error: function(model,response){
|
||||
var msg = Diaspora.I18n.t('contacts.error_add', { 'name':contact.closest('.stream_element').find('.name').text() });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeContactFromAspect: function(e){
|
||||
var contact = $(e.currentTarget);
|
||||
var aspect_membership = new app.models.AspectMembership({
|
||||
'id': contact.attr('data-membership_id')
|
||||
});
|
||||
|
||||
aspect_membership.destroy({
|
||||
success: function(model,response){
|
||||
contact.removeAttr('data-membership_id')
|
||||
.tooltip('destroy')
|
||||
.removeAttr('data-original-title')
|
||||
.removeClass("contact_remove-from-aspect").removeClass("circled-cross")
|
||||
.addClass("contact_add-to-aspect").addClass("circled-plus")
|
||||
.attr('title', Diaspora.I18n.t('contacts.add_contact'))
|
||||
.tooltip()
|
||||
.closest('.stream_element').removeClass('in_aspect');
|
||||
},
|
||||
error: function(model,response){
|
||||
var msg = Diaspora.I18n.t('contacts.error_remove', { 'name':contact.closest('.stream_element').find('.name').text() });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
searchContactList: function(e) {
|
||||
var query = new RegExp($(e.target).val(),'i');
|
||||
|
||||
$("#people_stream.stream.contacts .stream_element").each(function(){
|
||||
if($(this).find(".name").text().match(query)){
|
||||
$(this).show();
|
||||
} else {
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
this.stream.search($(e.target).val());
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -43,7 +43,15 @@ app.Router = Backbone.Router.extend({
|
|||
},
|
||||
|
||||
contacts: function() {
|
||||
app.contacts = new app.views.Contacts();
|
||||
app.aspect = new app.models.Aspect(gon.preloads.aspect);
|
||||
app.contacts = new app.collections.Contacts(app.parsePreload('contacts'));
|
||||
|
||||
var stream = new app.views.ContactStream({
|
||||
collection: app.contacts,
|
||||
el: $('.stream.contacts #contact_stream'),
|
||||
});
|
||||
|
||||
app.page = new app.pages.Contacts({stream: stream});
|
||||
},
|
||||
|
||||
conversations: function() {
|
||||
|
|
|
|||
77
app/assets/javascripts/app/views/contact_stream_view.js
Normal file
77
app/assets/javascripts/app/views/contact_stream_view.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.ContactStream = Backbone.View.extend({
|
||||
initialize: function() {
|
||||
this.itemCount = 0;
|
||||
this.perPage = 25;
|
||||
this.query = '';
|
||||
this.resultList = this.collection.toArray();
|
||||
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
|
||||
$(window).scroll(throttledScroll);
|
||||
this.on('renderContacts', this.renderContacts, this);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if( _.isEmpty(this.resultList) ) {
|
||||
var content = document.createDocumentFragment();
|
||||
content = '<div id="no_contacts" class="well">' +
|
||||
' <h4>' +
|
||||
Diaspora.I18n.t('contacts.search_no_results') +
|
||||
' </h4>' +
|
||||
'</div>';
|
||||
this.$el.html(content);
|
||||
} else {
|
||||
this.$el.html('');
|
||||
this.renderContacts();
|
||||
}
|
||||
},
|
||||
|
||||
renderContacts: function() {
|
||||
this.$el.addClass("loading");
|
||||
var content = document.createDocumentFragment();
|
||||
_.rest(_.first(this.resultList , this.itemCount + this.perPage), this.itemCount).forEach( function(item) {
|
||||
var view = new app.views.Contact({model: item});
|
||||
content.appendChild(view.render().el);
|
||||
});
|
||||
|
||||
var size = _.size(this.resultList);
|
||||
if( this.itemCount + this.perPage >= size ){
|
||||
this.itemCount = size;
|
||||
this.off('renderContacts');
|
||||
} else {
|
||||
this.itemCount += this.perPage;
|
||||
}
|
||||
this.$el.append(content);
|
||||
this.$el.removeClass("loading");
|
||||
},
|
||||
|
||||
search: function(query) {
|
||||
query = query.trim();
|
||||
if( query || this.query ) {
|
||||
this.off('renderContacts');
|
||||
this.on('renderContacts', this.renderContacts, this);
|
||||
this.itemCount = 0;
|
||||
if( query ) {
|
||||
this.query = query;
|
||||
var regex = new RegExp(query,'i');
|
||||
this.resultList = this.collection.filter(function(contact) {
|
||||
return regex.test(contact.get('person').name) ||
|
||||
regex.test(contact.get('person').diaspora_id);
|
||||
});
|
||||
} else {
|
||||
this.resultList = this.collection.toArray();
|
||||
this.query = '';
|
||||
}
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
infScroll: function() {
|
||||
if( this.$el.hasClass('loading') ) return;
|
||||
|
||||
var distanceTop = $(window).height() + $(window).scrollTop(),
|
||||
distanceBottom = $(document).height() - distanceTop;
|
||||
if(distanceBottom < 300) this.trigger('renderContacts');
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
72
app/assets/javascripts/app/views/contact_view.js
Normal file
72
app/assets/javascripts/app/views/contact_view.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Contact = app.views.Base.extend({
|
||||
templateName: 'contact',
|
||||
|
||||
events: {
|
||||
"click .contact_add-to-aspect" : "addContactToAspect",
|
||||
"click .contact_remove-from-aspect" : "removeContactFromAspect"
|
||||
},
|
||||
|
||||
tooltipSelector: '.contact_add-to-aspect, .contact_remove-from-aspect',
|
||||
|
||||
presenter: function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
person_id : this.model.get('person_id'),
|
||||
person : this.model.get('person'),
|
||||
in_aspect: (app.aspect && this.model.inAspect(app.aspect.get('id'))) ? 'in_aspect' : '',
|
||||
});
|
||||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
var self = this;
|
||||
var dropdownEl = this.$('.aspect_membership_dropdown.placeholder');
|
||||
if( dropdownEl.length == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO render me client side!!!
|
||||
var href = this.model.person.url() + '/aspect_membership_button?size=small';
|
||||
if( gon.bootstrap ) href += '&bootstrap=true';
|
||||
|
||||
$.get(href, function(resp) {
|
||||
dropdownEl.html(resp);
|
||||
new app.views.AspectMembership({el: $('.aspect_dropdown',dropdownEl)});
|
||||
|
||||
// UGLY (re-)attach the facebox
|
||||
self.$('a[rel*=facebox]').facebox();
|
||||
});
|
||||
},
|
||||
|
||||
addContactToAspect: function(){
|
||||
var self = this;
|
||||
this.model.aspect_memberships.create({
|
||||
'person_id': this.model.get('person_id'),
|
||||
'aspect_id': app.aspect.get('id')
|
||||
},{
|
||||
success: function(model,response){
|
||||
self.render();
|
||||
},
|
||||
error: function(model,response){
|
||||
var msg = Diaspora.I18n.t('contacts.error_add', { 'name': self.model.get('person').name });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeContactFromAspect: function(){
|
||||
var self = this;
|
||||
this.model.aspect_memberships
|
||||
.find(function(membership){ return membership.get('aspect').id == app.aspect.id; })
|
||||
.destroy({
|
||||
success: function(model,response){
|
||||
self.render();
|
||||
},
|
||||
error: function(model,response){
|
||||
var msg = Diaspora.I18n.t('contacts.error_remove', { 'name': self.model.get('person').name });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -66,8 +66,6 @@
|
|||
}
|
||||
|
||||
#no_contacts {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
background-color: #eee;
|
||||
color: $text-dark-grey;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<div id="{{guid}}">
|
||||
<div class="img">
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{{personImage this "small" "small"}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
</div>
|
||||
|
||||
<div class="bd">
|
||||
|
|
|
|||
23
app/assets/templates/contact_tpl.jst.hbs
Normal file
23
app/assets/templates/contact_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<div class="stream_element media contact {{in_aspect}}" id={{person_id}}>
|
||||
<div class="pull-right">
|
||||
{{{aspectMembershipIndicator this in_aspect}}}
|
||||
</div>
|
||||
|
||||
<div class="media-object pull-left">
|
||||
{{{personImage person 'small'}}}
|
||||
</div>
|
||||
|
||||
<div class="media-body">
|
||||
{{#linkToPerson person}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
|
||||
<div class="info diaspora_handle">
|
||||
{{person.diaspora_id}}
|
||||
</div>
|
||||
|
||||
<div class="info tags">
|
||||
{{{fmtTags person.profile.tags}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -3,26 +3,26 @@
|
|||
<div id='post-info' class='span8'>
|
||||
<div class="img pull-left">
|
||||
{{#if root}}
|
||||
{{#linkToPerson root.author}}
|
||||
{{#linkToAuthor root.author}}
|
||||
{{{personImage this 'medium'}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{else}}
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{{personImage this 'medium'}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="bd">
|
||||
<span class='author'>
|
||||
{{#if root}}
|
||||
{{#linkToPerson root.author}}
|
||||
{{#linkToAuthor root.author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{else}}
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
|
|
@ -69,14 +69,14 @@
|
|||
<div class='span8' id='reshare-info'>
|
||||
<i class='entypo retweet small pull-left'></i>
|
||||
<div class="img pull-left">
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{{personImage this 'small'}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
</div>
|
||||
<span class="author">
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
</span>
|
||||
<span class="post-time">
|
||||
<a href="/posts/{{id}}">
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
</span>
|
||||
<span>
|
||||
{{#each reshares}}
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{{personImage this 'small' 'micro'}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{/each}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -21,9 +21,9 @@
|
|||
</span>
|
||||
<span>
|
||||
{{#each likes}}
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{{personImage this 'small' 'micro'}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{/each}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{{#people}}
|
||||
{{#linkToPerson this}}
|
||||
{{#linkToAuthor this}}
|
||||
{{{personImage this "small"}}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
{{/people}}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@
|
|||
<div class='stream-frame-feedback'></div>
|
||||
|
||||
<div class="media author">
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
<div class="img">
|
||||
<div class="profile-image-container smaller" style="background-image : url('{{avatar.large}}')"></div>
|
||||
</div>
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
|
||||
<div class="bd">
|
||||
{{#linkToPerson author}}
|
||||
{{#linkToAuthor author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
{{/linkToAuthor}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ class AspectMembershipsController < ApplicationController
|
|||
respond_to do |format|
|
||||
format.json do
|
||||
if success
|
||||
render :json => {
|
||||
:person_id => contact.person_id,
|
||||
:aspect_ids => contact.aspects.map{|a| a.id}
|
||||
}
|
||||
render :json => AspectMembershipPresenter.new(membership).base_hash
|
||||
else
|
||||
render :text => membership.errors.full_messages, :status => 403
|
||||
end
|
||||
|
|
@ -57,7 +54,9 @@ class AspectMembershipsController < ApplicationController
|
|||
flash.now[:notice] = I18n.t('aspects.add_to_aspect.success')
|
||||
respond_with do |format|
|
||||
format.json do
|
||||
render :json => AspectMembership.where(:contact_id => @contact.id, :aspect_id => @aspect.id).first.to_json
|
||||
render :json => AspectMembershipPresenter.new(
|
||||
AspectMembership.where(:contact_id => @contact.id, :aspect_id => @aspect.id).first)
|
||||
.base_hash
|
||||
end
|
||||
|
||||
format.all { redirect_to :back }
|
||||
|
|
|
|||
|
|
@ -40,32 +40,24 @@ class ContactsController < ApplicationController
|
|||
|
||||
@contacts = contacts_by_type(type)
|
||||
@contacts_size = @contacts.length
|
||||
gon.preloads[:contacts] = @contacts.map{ |c| ContactPresenter.new(c, current_user).full_hash_with_person }
|
||||
end
|
||||
|
||||
def contacts_by_type(type)
|
||||
contacts = case type
|
||||
case type
|
||||
when "all"
|
||||
[current_user.contacts]
|
||||
current_user.contacts
|
||||
when "only_sharing"
|
||||
[current_user.contacts.only_sharing]
|
||||
current_user.contacts.only_sharing
|
||||
when "receiving"
|
||||
[current_user.contacts.receiving]
|
||||
current_user.contacts.receiving
|
||||
when "by_aspect"
|
||||
@aspect = current_user.aspects.find(params[:a_id])
|
||||
@contacts_in_aspect = @aspect.contacts
|
||||
@contacts_not_in_aspect = current_user.contacts.where.not(contacts: {id: @contacts_in_aspect.pluck(:id) })
|
||||
[@contacts_in_aspect, @contacts_not_in_aspect].map {|relation|
|
||||
relation.includes(:aspect_memberships)
|
||||
}
|
||||
gon.preloads[:aspect] = AspectPresenter.new(@aspect).as_json
|
||||
current_user.contacts
|
||||
else
|
||||
raise ArgumentError, "unknown type #{type}"
|
||||
end
|
||||
|
||||
contacts.map {|relation|
|
||||
relation.includes(:person => :profile).to_a.tap {|contacts|
|
||||
contacts.sort_by! {|contact| contact.person.name }
|
||||
}
|
||||
}.inject(:+).paginate(:page => params[:page], :per_page => 25)
|
||||
end
|
||||
|
||||
def set_up_contacts_mobile
|
||||
|
|
|
|||
|
|
@ -1,25 +1,9 @@
|
|||
module ContactsHelper
|
||||
def contact_aspect_dropdown(contact)
|
||||
membership = contact.aspect_memberships.where(:aspect_id => @aspect.id).first unless @aspect.nil?
|
||||
|
||||
if membership
|
||||
content_tag(:i, nil, :class => 'entypo circled-cross contact_remove-from-aspect',
|
||||
:title => t('contacts.index.remove_contact'),
|
||||
'data-aspect_id' => @aspect.id,
|
||||
'data-person_id' => contact.person_id,
|
||||
'data-membership_id' => membership.id )
|
||||
|
||||
elsif @aspect.nil?
|
||||
render :partial => 'people/relationship_action',
|
||||
:locals => { :person => contact.person,
|
||||
:contact => contact,
|
||||
:current_user => current_user }
|
||||
else
|
||||
content_tag(:i, nil, :class => 'entypo circled-plus contact_add-to-aspect',
|
||||
:title => t('contacts.index.add_contact'),
|
||||
'data-aspect_id' => @aspect.id,
|
||||
'data-person_id' => contact.person_id )
|
||||
end
|
||||
render :partial => 'people/relationship_action',
|
||||
:locals => { :person => contact.person,
|
||||
:contact => contact,
|
||||
:current_user => current_user }
|
||||
end
|
||||
|
||||
def start_a_conversation_link(aspect, contacts_size)
|
||||
|
|
|
|||
11
app/presenters/aspect_membership_presenter.rb
Normal file
11
app/presenters/aspect_membership_presenter.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
class AspectMembershipPresenter < BasePresenter
|
||||
def initialize(membership)
|
||||
@membership = membership
|
||||
end
|
||||
|
||||
def base_hash
|
||||
{ id: @membership.id,
|
||||
aspect: AspectPresenter.new(@membership.aspect).as_json,
|
||||
}
|
||||
end
|
||||
end
|
||||
17
app/presenters/contact_presenter.rb
Normal file
17
app/presenters/contact_presenter.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
class ContactPresenter < BasePresenter
|
||||
def base_hash
|
||||
{ id: id,
|
||||
person_id: person_id
|
||||
}
|
||||
end
|
||||
|
||||
def full_hash
|
||||
base_hash.merge({
|
||||
aspect_memberships: aspect_memberships.map{ |membership| AspectMembershipPresenter.new(membership).base_hash }
|
||||
})
|
||||
end
|
||||
|
||||
def full_hash_with_person
|
||||
full_hash.merge({person: PersonPresenter.new(person).full_hash_with_profile})
|
||||
end
|
||||
end
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
- membership = contact.aspect_memberships.where(:aspect_id => @aspect.id).first unless @aspect.nil?
|
||||
.media.stream_element{:id => contact.person_id, :class => ("in_aspect" if membership)}
|
||||
.pull-right
|
||||
= contact_aspect_dropdown(contact)
|
||||
.media-object.pull-left
|
||||
= person_image_link(contact.person, :size => :thumb_small)
|
||||
.media-body
|
||||
= person_link(contact.person, :class => 'name')
|
||||
.info.diaspora_handle
|
||||
= contact.person_diaspora_handle
|
||||
.info.tags
|
||||
= Diaspora::Taggable.format_tags(contact.person.profile.tag_string)
|
||||
|
|
@ -11,8 +11,9 @@
|
|||
= render 'contacts/header'
|
||||
|
||||
- if @contacts_size > 0
|
||||
= render @contacts
|
||||
= will_paginate @contacts
|
||||
#contact_stream
|
||||
-# JS
|
||||
|
||||
- else
|
||||
.no_contacts
|
||||
%h3
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ en:
|
|||
remove_contact: "Remove contact"
|
||||
error_add: "Couldn't add <%= name %> to the aspect :("
|
||||
error_remove: "Couldn't remove <%= name %> from the aspect :("
|
||||
search_no_results: "No contacts found"
|
||||
|
||||
my_activity: "My Activity"
|
||||
my_stream: "Stream"
|
||||
|
|
|
|||
|
|
@ -72,14 +72,14 @@ describe AspectMembershipsController, :type => :controller do
|
|||
end
|
||||
|
||||
context 'json' do
|
||||
it 'returns a list of aspect ids for the person' do
|
||||
it 'returns the aspect membership' do
|
||||
post :create,
|
||||
:format => :json,
|
||||
:person_id => @person.id,
|
||||
:aspect_id => @aspect0.id
|
||||
|
||||
contact = @controller.current_user.contact_for(@person)
|
||||
expect(response.body).to eq(contact.aspect_memberships.first.to_json)
|
||||
expect(response.body).to eq(AspectMembershipPresenter.new(contact.aspect_memberships.first).base_hash.to_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,12 +10,20 @@ describe ContactsController, :type => :controller do
|
|||
AppConfig.chat.enabled = true
|
||||
@aspect = bob.aspects.create(:name => "another aspect")
|
||||
bob.share_with alice.person, @aspect
|
||||
bob.share_with eve.person, @aspect
|
||||
sign_in :user, bob
|
||||
end
|
||||
|
||||
it "generates a jasmine fixture", :fixture => true do
|
||||
it "generates the aspects_manage fixture", :fixture => true do
|
||||
get :index, :a_id => @aspect.id
|
||||
save_fixture(html_for("body"), "aspects_manage")
|
||||
end
|
||||
|
||||
it "generates the contacts_json fixture", :fixture => true do
|
||||
json = bob.contacts.map { |c|
|
||||
ContactPresenter.new(c, bob).full_hash_with_person
|
||||
}.to_json
|
||||
save_fixture(json, "contacts_json")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
37
spec/javascripts/app/collections/contacts_collection_spec.js
Normal file
37
spec/javascripts/app/collections/contacts_collection_spec.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
describe("app.collections.Contacts", function(){
|
||||
beforeEach(function(){
|
||||
this.collection = new app.collections.Contacts();
|
||||
});
|
||||
|
||||
describe("comparator", function() {
|
||||
beforeEach(function(){
|
||||
this.aspect = new app.models.Aspect({id: 42, name: "cats"});
|
||||
this.con1 = new app.models.Contact({
|
||||
person: { name: "aaa" },
|
||||
aspect_memberships: []
|
||||
});
|
||||
this.con2 = new app.models.Contact({
|
||||
person: { name: "aaa" },
|
||||
aspect_memberships: [{id: 23, aspect: this.aspect}]
|
||||
});
|
||||
this.con3 = new app.models.Contact({
|
||||
person: { name: "zzz" },
|
||||
aspect_memberships: [{id: 23, aspect: this.aspect}]
|
||||
});
|
||||
});
|
||||
|
||||
it("should compare the username if app.aspect is not present", function() {
|
||||
expect(this.collection.comparator(this.con1, this.con3)).toBeLessThan(0);
|
||||
});
|
||||
|
||||
it("should compare the aspect memberships if app.aspect is present", function() {
|
||||
app.aspect = this.aspect;
|
||||
expect(this.collection.comparator(this.con1, this.con3)).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("should compare the username if the contacts have equal aspect memberships", function() {
|
||||
app.aspect = this.aspect;
|
||||
expect(this.collection.comparator(this.con2, this.con3)).toBeLessThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
20
spec/javascripts/app/models/contact_spec.js
Normal file
20
spec/javascripts/app/models/contact_spec.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
describe("app.models.Contact", function() {
|
||||
|
||||
beforeEach(function(){
|
||||
this.aspect = factory.aspect();
|
||||
this.contact = new app.models.Contact({
|
||||
person: { name: "aaa" },
|
||||
aspect_memberships: [{id: 42, aspect: this.aspect}]
|
||||
});
|
||||
});
|
||||
|
||||
describe("inAspect", function(){
|
||||
it("returns true if the contact has been added to the aspect", function(){
|
||||
expect(this.contact.inAspect(this.aspect.id)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("returns false if the contact hasn't been added to the aspect", function(){
|
||||
expect(this.contact.inAspect(this.aspect.id+1)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
101
spec/javascripts/app/pages/contacts_spec.js
Normal file
101
spec/javascripts/app/pages/contacts_spec.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
describe("app.pages.Contacts", function(){
|
||||
beforeEach(function() {
|
||||
spec.loadFixture("aspects_manage");
|
||||
this.view = new app.pages.Contacts({
|
||||
stream: {
|
||||
render: function(){}
|
||||
}
|
||||
});
|
||||
Diaspora.I18n.load({
|
||||
contacts: {
|
||||
aspect_list_is_visible: "Contacts in this aspect are able to see each other.",
|
||||
aspect_list_is_not_visible: "Contacts in this aspect are not able to see each other.",
|
||||
aspect_chat_is_enabled: "Contacts in this aspect are able to chat with you.",
|
||||
aspect_chat_is_not_enabled: "Contacts in this aspect are not able to chat with you.",
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
context('toggle chat privilege', function() {
|
||||
beforeEach(function() {
|
||||
this.chat_toggle = $("#chat_privilege_toggle");
|
||||
this.chat_icon = $("#chat_privilege_toggle .entypo");
|
||||
});
|
||||
|
||||
it('updates the title for the tooltip', function() {
|
||||
expect(this.chat_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_chat_is_not_enabled")
|
||||
);
|
||||
this.chat_toggle.trigger('click');
|
||||
expect(this.chat_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_chat_is_enabled")
|
||||
);
|
||||
});
|
||||
|
||||
it('toggles the chat icon', function() {
|
||||
expect(this.chat_icon.hasClass('enabled')).toBeFalsy();
|
||||
this.chat_toggle.trigger('click');
|
||||
expect(this.chat_icon.hasClass('enabled')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
context('toggle contacts visibility', function() {
|
||||
beforeEach(function() {
|
||||
this.visibility_toggle = $("#contacts_visibility_toggle");
|
||||
this.lock_icon = $("#contacts_visibility_toggle .entypo");
|
||||
});
|
||||
|
||||
it('updates the title for the tooltip', function() {
|
||||
expect(this.lock_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_list_is_visible")
|
||||
);
|
||||
|
||||
this.visibility_toggle.trigger('click');
|
||||
|
||||
expect(this.lock_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_list_is_not_visible")
|
||||
);
|
||||
});
|
||||
|
||||
it('toggles the lock icon', function() {
|
||||
expect(this.lock_icon.hasClass('lock-open')).toBeTruthy();
|
||||
expect(this.lock_icon.hasClass('lock')).toBeFalsy();
|
||||
|
||||
this.visibility_toggle.trigger('click');
|
||||
|
||||
expect(this.lock_icon.hasClass('lock')).toBeTruthy();
|
||||
expect(this.lock_icon.hasClass('lock-open')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
context('show aspect name form', function() {
|
||||
beforeEach(function() {
|
||||
this.button = $('#change_aspect_name');
|
||||
});
|
||||
|
||||
it('shows the form', function() {
|
||||
expect($('#aspect_name_form').css('display')).toBe('none');
|
||||
this.button.trigger('click');
|
||||
expect($('#aspect_name_form').css('display')).not.toBe('none');
|
||||
});
|
||||
|
||||
it('hides the aspect name', function() {
|
||||
expect($('.header > h3').css('display')).not.toBe('none');
|
||||
this.button.trigger('click');
|
||||
expect($('.header > h3').css('display')).toBe('none');
|
||||
});
|
||||
});
|
||||
|
||||
context('search contact list', function() {
|
||||
beforeEach(function() {
|
||||
this.searchinput = $('#contact_list_search');
|
||||
});
|
||||
|
||||
it('calls stream.search', function() {
|
||||
this.view.stream.search = jasmine.createSpy();
|
||||
this.searchinput.val("Username");
|
||||
this.searchinput.trigger('keyup');
|
||||
expect(this.view.stream.search).toHaveBeenCalledWith("Username");
|
||||
});
|
||||
});
|
||||
});
|
||||
77
spec/javascripts/app/views/contact_stream_view_spec.js
Normal file
77
spec/javascripts/app/views/contact_stream_view_spec.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
describe("app.views.ContactStream", function() {
|
||||
beforeEach(function() {
|
||||
loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}});
|
||||
spec.loadFixture("aspects_manage");
|
||||
this.contacts = new app.collections.Contacts($.parseJSON(spec.readFixture("contacts_json")));
|
||||
app.aspect = new app.models.Aspect(this.contacts.first().get('aspect_memberships')[0].aspect);
|
||||
this.view = new app.views.ContactStream({
|
||||
collection : this.contacts,
|
||||
el: $('.stream.contacts #contact_stream')
|
||||
});
|
||||
|
||||
this.view.perPage=1;
|
||||
|
||||
//clean the page
|
||||
this.view.$el.html('');
|
||||
});
|
||||
|
||||
describe("initialize", function() {
|
||||
it("binds an infinite scroll listener", function() {
|
||||
spyOn($.fn, "scroll");
|
||||
new app.views.ContactStream({collection : this.contacts});
|
||||
expect($.fn.scroll).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("search", function() {
|
||||
it("filters the contacts", function() {
|
||||
this.view.render();
|
||||
expect(this.view.$el.html()).toContain("alice");
|
||||
this.view.search("eve");
|
||||
expect(this.view.$el.html()).not.toContain("alice");
|
||||
expect(this.view.$el.html()).toContain("eve");
|
||||
});
|
||||
});
|
||||
|
||||
describe("infScroll", function() {
|
||||
beforeEach(function() {
|
||||
this.view.off("renderContacts");
|
||||
this.fn = jasmine.createSpy();
|
||||
this.view.on("renderContacts", this.fn);
|
||||
spyOn($.fn, "height").and.returnValue(0);
|
||||
spyOn($.fn, "scrollTop").and.returnValue(100);
|
||||
});
|
||||
|
||||
it("triggers renderContacts when the user is at the bottom of the page", function() {
|
||||
this.view.infScroll();
|
||||
expect(this.fn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("render", function() {
|
||||
beforeEach(function() {
|
||||
spyOn(this.view, "renderContacts");
|
||||
});
|
||||
|
||||
it("calls renderContacts", function() {
|
||||
this.view.render();
|
||||
expect(this.view.renderContacts).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("renderContacts", function() {
|
||||
beforeEach(function() {
|
||||
this.view.off("renderContacts");
|
||||
this.view.renderContacts();
|
||||
});
|
||||
|
||||
it("renders perPage contacts", function() {
|
||||
expect(this.view.$el.find('.stream_element.contact').length).toBe(1);
|
||||
});
|
||||
|
||||
it("renders more contacts when called a second time", function() {
|
||||
this.view.renderContacts();
|
||||
expect(this.view.$el.find('.stream_element.contact').length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
136
spec/javascripts/app/views/contact_view_spec.js
Normal file
136
spec/javascripts/app/views/contact_view_spec.js
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
describe("app.views.Contact", function(){
|
||||
beforeEach(function() {
|
||||
this.aspect1 = factory.aspect({id: 1});
|
||||
this.aspect2 = factory.aspect({id: 2});
|
||||
|
||||
this.model = new app.models.Contact({
|
||||
person_id: 42,
|
||||
person: { id: 42, name: 'alice' },
|
||||
aspect_memberships: [{id: 23, aspect: this.aspect1}]
|
||||
});
|
||||
this.view = new app.views.Contact({ model: this.model });
|
||||
Diaspora.I18n.load({
|
||||
contacts: {
|
||||
add_contact: "Add contact",
|
||||
remove_contact: "Remove contact",
|
||||
error_add: "Couldn't add <%= name %> to the aspect :(",
|
||||
error_remove: "Couldn't remove <%= name %> from the aspect :("
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
context("#presenter", function() {
|
||||
it("contains necessary elements", function() {
|
||||
app.aspect = this.aspect1;
|
||||
expect(this.view.presenter()).toEqual(jasmine.objectContaining({
|
||||
person_id: 42,
|
||||
person: jasmine.objectContaining({id: 42, name: 'alice'}),
|
||||
in_aspect: 'in_aspect'
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
context('add contact to aspect', function() {
|
||||
beforeEach(function() {
|
||||
app.aspect = this.aspect2;
|
||||
this.view.render();
|
||||
this.button = this.view.$el.find('.contact_add-to-aspect');
|
||||
this.contact = this.view.$el.find('.stream_element.contact');
|
||||
this.aspect_membership = {id: 42, aspect: app.aspect.toJSON()};
|
||||
this.response = JSON.stringify(this.aspect_membership);
|
||||
});
|
||||
|
||||
it('sends a correct ajax request', function() {
|
||||
this.button.trigger('click');
|
||||
var obj = $.parseJSON(jasmine.Ajax.requests.mostRecent().params);
|
||||
expect(obj.person_id).toBe(this.model.get('person_id'));
|
||||
expect(obj.aspect_id).toBe(app.aspect.get('id'));
|
||||
});
|
||||
|
||||
it('adds a aspect_membership to the contact', function() {
|
||||
expect(this.model.aspect_memberships.length).toBe(1);
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: this.response
|
||||
});
|
||||
expect(this.model.aspect_memberships.length).toBe(2);
|
||||
});
|
||||
|
||||
it('calls render', function() {
|
||||
spyOn(this.view, 'render');
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: this.response
|
||||
});
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('displays a flash message on errors', function(){
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 400, // fail
|
||||
});
|
||||
expect($('[id^="flash"]')).toBeErrorFlashMessage(
|
||||
Diaspora.I18n.t(
|
||||
'contacts.error_add',
|
||||
{name: this.model.get('person').name}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('remove contact from aspect', function() {
|
||||
beforeEach(function() {
|
||||
app.aspect = this.aspect1;
|
||||
this.view.render();
|
||||
this.button = this.view.$el.find('.contact_remove-from-aspect');
|
||||
this.contact = this.view.$el.find('.stream_element.contact');
|
||||
this.aspect_membership = this.model.aspect_memberships.first().toJSON();
|
||||
this.response = JSON.stringify(this.aspect_membership);
|
||||
});
|
||||
|
||||
it('sends a correct ajax request', function() {
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
expect(jasmine.Ajax.requests.mostRecent().url).toBe(
|
||||
"/aspect_memberships/"+this.aspect_membership.id
|
||||
);
|
||||
});
|
||||
|
||||
it('removes the aspect_membership from the contact', function() {
|
||||
expect(this.model.aspect_memberships.length).toBe(1);
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: this.response
|
||||
});
|
||||
expect(this.model.aspect_memberships.length).toBe(0);
|
||||
});
|
||||
|
||||
it('calls render', function() {
|
||||
spyOn(this.view, 'render');
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: this.response,
|
||||
});
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('displays a flash message on errors', function(){
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 400, // fail
|
||||
});
|
||||
expect($('[id^="flash"]')).toBeErrorFlashMessage(
|
||||
Diaspora.I18n.t(
|
||||
'contacts.error_remove',
|
||||
{name: this.model.get('person').name}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
describe("app.views.Contacts", function(){
|
||||
beforeEach(function() {
|
||||
spec.loadFixture("aspects_manage");
|
||||
this.view = new app.views.Contacts();
|
||||
Diaspora.I18n.load({
|
||||
contacts: {
|
||||
add_contact: "Add contact",
|
||||
aspect_list_is_visible: "Contacts in this aspect are able to see each other.",
|
||||
aspect_list_is_not_visible: "Contacts in this aspect are not able to see each other.",
|
||||
aspect_chat_is_enabled: "Contacts in this aspect are able to chat with you.",
|
||||
aspect_chat_is_not_enabled: "Contacts in this aspect are not able to chat with you.",
|
||||
remove_contact: "Remove contact",
|
||||
error_add: "Couldn't add <%= name %> to the aspect :(",
|
||||
error_remove: "Couldn't remove <%= name %> from the aspect :("
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
context('toggle chat privilege', function() {
|
||||
beforeEach(function() {
|
||||
this.chat_toggle = $("#chat_privilege_toggle");
|
||||
this.chat_icon = $("#chat_privilege_toggle .entypo");
|
||||
});
|
||||
|
||||
it('updates the title for the tooltip', function() {
|
||||
expect(this.chat_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_chat_is_not_enabled")
|
||||
);
|
||||
this.chat_toggle.trigger('click');
|
||||
expect(this.chat_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_chat_is_enabled")
|
||||
);
|
||||
});
|
||||
|
||||
it('toggles the chat icon', function() {
|
||||
expect(this.chat_icon.hasClass('enabled')).toBeFalsy;
|
||||
this.chat_toggle.trigger('click');
|
||||
expect(this.chat_icon.hasClass('enabled')).toBeTruethy;
|
||||
});
|
||||
});
|
||||
|
||||
context('toggle contacts visibility', function() {
|
||||
beforeEach(function() {
|
||||
this.visibility_toggle = $("#contacts_visibility_toggle");
|
||||
this.lock_icon = $("#contacts_visibility_toggle .entypo");
|
||||
});
|
||||
|
||||
it('updates the title for the tooltip', function() {
|
||||
expect(this.lock_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_list_is_visible")
|
||||
);
|
||||
|
||||
this.visibility_toggle.trigger('click');
|
||||
|
||||
expect(this.lock_icon.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t("contacts.aspect_list_is_not_visible")
|
||||
);
|
||||
});
|
||||
|
||||
it('toggles the lock icon', function() {
|
||||
expect(this.lock_icon.hasClass('lock-open')).toBeTruethy;
|
||||
expect(this.lock_icon.hasClass('lock')).toBeFalsy;
|
||||
|
||||
this.visibility_toggle.trigger('click');
|
||||
|
||||
expect(this.lock_icon.hasClass('lock')).toBeTruethy;
|
||||
expect(this.lock_icon.hasClass('lock-open')).toBeFalsy;
|
||||
});
|
||||
});
|
||||
|
||||
context('show aspect name form', function() {
|
||||
beforeEach(function() {
|
||||
this.button = $('#change_aspect_name');
|
||||
});
|
||||
|
||||
it('shows the form', function() {
|
||||
expect($('#aspect_name_form').css('display')).toBe('none');
|
||||
this.button.trigger('click');
|
||||
expect($('#aspect_name_form').css('display')).not.toBe('none');
|
||||
});
|
||||
|
||||
it('hides the aspect name', function() {
|
||||
expect($('.header > h3').css('display')).not.toBe('none');
|
||||
this.button.trigger('click');
|
||||
expect($('.header > h3').css('display')).toBe('none');
|
||||
});
|
||||
});
|
||||
|
||||
context('add contact to aspect', function() {
|
||||
beforeEach(function() {
|
||||
this.contact = $('#people_stream .stream_element').last();
|
||||
this.button = this.contact.find('.contact_add-to-aspect');
|
||||
this.person_id = this.button.attr('data-person_id');
|
||||
this.aspect_id = this.button.attr('data-aspect_id');
|
||||
});
|
||||
|
||||
it('sends a correct ajax request', function() {
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
var obj = $.parseJSON(jasmine.Ajax.requests.mostRecent().params);
|
||||
expect(obj.person_id).toBe(this.person_id);
|
||||
expect(obj.aspect_id).toBe(this.aspect_id);
|
||||
});
|
||||
|
||||
it('adds a membership id to the contact', function() {
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: '{ "id": 42 }'
|
||||
});
|
||||
expect(this.button.attr('data-membership_id')).toBe('42');
|
||||
});
|
||||
|
||||
it('displays a flash message on errors', function(){
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 400, // fail
|
||||
});
|
||||
expect($('[id^="flash"]')).toBeErrorFlashMessage(
|
||||
Diaspora.I18n.t(
|
||||
'contacts.error_add',
|
||||
{name: this.contact.find('.name').text()}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('changes the appearance of the contact', function() {
|
||||
expect(this.button.hasClass('contact_add-to-aspect')).toBeTruethy;
|
||||
expect(this.button.hasClass('circled-cross')).toBeTruethy;
|
||||
expect(this.contact.hasClass('in_aspect')).toBeTruethy;
|
||||
expect(this.button.hasClass('contact_remove-from-aspect')).toBeFalsy;
|
||||
expect(this.button.hasClass('circled-plus')).toBeFalsy;
|
||||
expect(this.button.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t('contacts.add_contact')
|
||||
);
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_add-to-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: '{ "id": 42 }'
|
||||
});
|
||||
expect(this.button.hasClass('contact_add-to-aspect')).toBeFalsy;
|
||||
expect(this.button.hasClass('circled-cross')).toBeFalsy;
|
||||
expect(this.contact.hasClass('in_aspect')).toBeFalsy;
|
||||
expect(this.button.hasClass('contact_remove-from-aspect')).toBeTruethy;
|
||||
expect(this.button.hasClass('circled-plus')).toBeTruethy;
|
||||
expect(this.button.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t('contacts.remove_contact')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('remove contact from aspect', function() {
|
||||
beforeEach(function() {
|
||||
this.contact = $('#people_stream .stream_element').first();
|
||||
this.button = this.contact.find('.contact_remove-from-aspect');
|
||||
this.person_id = this.button.attr('data-person_id');
|
||||
this.aspect_id = this.button.attr('data-aspect_id');
|
||||
this.membership_id = this.button.attr('data-membership_id');
|
||||
|
||||
});
|
||||
|
||||
it('sends a correct ajax request', function() {
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
expect(jasmine.Ajax.requests.mostRecent().url).toBe(
|
||||
"/aspect_memberships/"+this.membership_id
|
||||
);
|
||||
});
|
||||
|
||||
it('removes the membership id from the contact', function() {
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: '{}'
|
||||
});
|
||||
expect(this.button.attr('data-membership_id')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('displays a flash message on errors', function(){
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 400, // fail
|
||||
});
|
||||
expect($('[id^="flash"]')).toBeErrorFlashMessage(
|
||||
Diaspora.I18n.t(
|
||||
'contacts.error_remove',
|
||||
{name: this.contact.find('.name').text()}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('changes the appearance of the contact', function() {
|
||||
expect(this.button.hasClass('contact_add-to-aspect')).toBeFalsy;
|
||||
expect(this.button.hasClass('circled-cross')).toBeFalsy;
|
||||
expect(this.contact.hasClass('in_aspect')).toBeFalsy;
|
||||
expect(this.button.hasClass('contact_remove-from-aspect')).toBeTruethy;
|
||||
expect(this.button.hasClass('circled-plus')).toBeTruethy;
|
||||
expect(this.button.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t('contacts.remove_contact')
|
||||
);
|
||||
|
||||
jasmine.Ajax.install();
|
||||
$('.contact_remove-from-aspect',this.contact).trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().response({
|
||||
status: 200, // success
|
||||
responseText: '{}'
|
||||
});
|
||||
|
||||
expect(this.button.hasClass('contact_add-to-aspect')).toBeTruethy;
|
||||
expect(this.button.hasClass('circled-cross')).toBeTruethy;
|
||||
expect(this.contact.hasClass('in_aspect')).toBeTruethy;
|
||||
expect(this.button.hasClass('contact_remove-from-aspect')).toBeFalsy;
|
||||
expect(this.button.hasClass('circled-plus')).toBeFalsy;
|
||||
expect(this.button.attr('data-original-title')).toBe(
|
||||
Diaspora.I18n.t('contacts.add_contact')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('search contact list', function() {
|
||||
beforeEach(function() {
|
||||
this.searchinput = $('#contact_list_search');
|
||||
this.username = $('.stream_element .name').first().text();
|
||||
});
|
||||
|
||||
it('filters the contact list by name', function() {
|
||||
expect($('.stream_element').length).toBeGreaterThan(1);
|
||||
this.searchinput.val(this.username);
|
||||
this.searchinput.trigger('keyup');
|
||||
expect($('.stream_element:visible').length).toBe(1);
|
||||
expect($('.stream_element:visible .name').first().text()).toBe(this.username);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -63,13 +63,13 @@ describe("app.views.Notifications", function(){
|
|||
|
||||
it('toggles the unread class and changes the title', function() {
|
||||
this.view.updateView(this.readN.data('guid'), this.readN.data('type'), true);
|
||||
expect(this.readN.hasClass('unread')).toBeTruethy;
|
||||
expect(this.readN.hasClass('read')).toBeFalsy;
|
||||
expect(this.readN.hasClass('unread')).toBeTruthy();
|
||||
expect(this.readN.hasClass('read')).toBeFalsy();
|
||||
expect(this.readN.find('.unread-toggle .entypo').data('original-title')).toBe(Diaspora.I18n.t('notifications.mark_read'));
|
||||
|
||||
this.view.updateView(this.readN.data('guid'), this.readN.data('type'), false);
|
||||
expect(this.readN.hasClass('read')).toBeTruethy;
|
||||
expect(this.readN.hasClass('unread')).toBeFalsy;
|
||||
expect(this.readN.hasClass('read')).toBeTruthy();
|
||||
expect(this.readN.hasClass('unread')).toBeFalsy();
|
||||
expect(this.readN.find('.unread-toggle .entypo').data('original-title')).toBe(Diaspora.I18n.t('notifications.mark_unread'));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
15
spec/presenters/aspect_membership_presenter_spec.rb
Normal file
15
spec/presenters/aspect_membership_presenter_spec.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe AspectMembershipPresenter do
|
||||
before do
|
||||
@am = alice.aspects.where(:name => "generic").first.aspect_memberships.first
|
||||
@presenter = AspectMembershipPresenter.new(@am)
|
||||
end
|
||||
|
||||
describe '#base_hash' do
|
||||
it 'works' do
|
||||
expect(@presenter.base_hash).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
26
spec/presenters/contact_presenter_spec.rb
Normal file
26
spec/presenters/contact_presenter_spec.rb
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ContactPresenter do
|
||||
before do
|
||||
@presenter = ContactPresenter.new(alice.contact_for(bob.person))
|
||||
end
|
||||
|
||||
describe '#base_hash' do
|
||||
it 'works' do
|
||||
expect(@presenter.base_hash).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
describe '#full_hash' do
|
||||
it 'works' do
|
||||
expect(@presenter.full_hash).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
describe '#full_hash_with_person' do
|
||||
it 'works' do
|
||||
expect(@presenter.full_hash_with_person).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
Loading…
Reference in a new issue