Refactor app.views.AspectMembership
in order to support adding new aspect to a dropdown without full page reload
This commit is contained in:
parent
15e0f88758
commit
923fb8a763
44 changed files with 526 additions and 285 deletions
|
|
@ -120,9 +120,6 @@ var app = {
|
|||
|
||||
setupGlobalViews: function() {
|
||||
app.hovercard = new app.views.Hovercard();
|
||||
$('.aspect_membership_dropdown').each(function(){
|
||||
new app.views.AspectMembership({el: this});
|
||||
});
|
||||
app.sidebar = new app.views.Sidebar();
|
||||
app.backToTop = new app.views.BackToTop({el: $(document)});
|
||||
app.flashMessages = new app.views.FlashMessages({el: $("#flash-container")});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
// @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
|
||||
model: app.models.AspectMembership,
|
||||
|
||||
findByAspectId: function(id) {
|
||||
return this.find(function(membership) { return membership.belongsToAspect(id); });
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
7
app/assets/javascripts/app/collections/aspects.js
Normal file
7
app/assets/javascripts/app/collections/aspects.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Aspects = Backbone.Collection.extend({
|
||||
model: app.models.Aspect,
|
||||
url: "/aspects"
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -5,6 +5,11 @@
|
|||
* (only valid for the context of the current user)
|
||||
*/
|
||||
app.models.AspectMembership = Backbone.Model.extend({
|
||||
urlRoot: "/aspect_memberships"
|
||||
urlRoot: "/aspect_memberships",
|
||||
|
||||
belongsToAspect: function(aspectId) {
|
||||
var aspect = this.get("aspect");
|
||||
return aspect && aspect.id === aspectId;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@
|
|||
app.models.Contact = Backbone.Model.extend({
|
||||
initialize : function() {
|
||||
this.aspectMemberships = new app.collections.AspectMemberships(this.get("aspect_memberships"));
|
||||
if(this.get("person")) { this.person = new app.models.Person(this.get("person")); }
|
||||
if (this.get("person")) {
|
||||
this.person = new app.models.Person(this.get("person"));
|
||||
this.person.contact = this;
|
||||
}
|
||||
},
|
||||
|
||||
inAspect : function(id) {
|
||||
return this.aspectMemberships.any(function(membership){ return membership.get("aspect").id === id; });
|
||||
return this.aspectMemberships.any(function(membership) { return membership.belongsToAspect(id); });
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -6,8 +6,13 @@ app.models.Person = Backbone.Model.extend({
|
|||
},
|
||||
|
||||
initialize: function() {
|
||||
if( this.get('profile') )
|
||||
this.profile = new app.models.Profile(this.get('profile'));
|
||||
if (this.get("profile")) {
|
||||
this.profile = new app.models.Profile(this.get("profile"));
|
||||
}
|
||||
if (this.get("contact")) {
|
||||
this.contact = new app.models.Contact(this.get("contact"));
|
||||
this.contact.person = this;
|
||||
}
|
||||
},
|
||||
|
||||
isSharing: function() {
|
||||
|
|
|
|||
20
app/assets/javascripts/app/pages/getting_started.js
Normal file
20
app/assets/javascripts/app/pages/getting_started.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
app.pages.GettingStarted = app.views.Base.extend({
|
||||
el: "#hello-there",
|
||||
|
||||
templateName: false,
|
||||
|
||||
subviews: {
|
||||
".aspect_membership_dropdown": "aspectMembershipView"
|
||||
},
|
||||
|
||||
initialize: function(opts) {
|
||||
this.inviter = opts.inviter;
|
||||
app.events.on("aspect:create", this.render, this);
|
||||
},
|
||||
|
||||
aspectMembershipView: function() {
|
||||
return new app.views.AspectMembership({person: this.inviter, dropdownMayCreateNewAspect: true});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -5,6 +5,7 @@ app.Router = Backbone.Router.extend({
|
|||
"help/:section": "help",
|
||||
"help/": "help",
|
||||
"help": "help",
|
||||
"getting_started": "gettingStarted",
|
||||
"contacts": "contacts",
|
||||
"conversations": "conversations",
|
||||
"user/edit": "settings",
|
||||
|
|
@ -60,6 +61,7 @@ app.Router = Backbone.Router.extend({
|
|||
contacts: function() {
|
||||
app.aspect = new app.models.Aspect(gon.preloads.aspect);
|
||||
app.contacts = new app.collections.Contacts(app.parsePreload("contacts"));
|
||||
this._loadAspects();
|
||||
|
||||
var stream = new app.views.ContactStream({
|
||||
collection: app.contacts,
|
||||
|
|
@ -69,6 +71,13 @@ app.Router = Backbone.Router.extend({
|
|||
app.page = new app.pages.Contacts({stream: stream});
|
||||
},
|
||||
|
||||
gettingStarted: function() {
|
||||
this._loadAspects();
|
||||
this.renderPage(function() {
|
||||
return new app.pages.GettingStarted({inviter: new app.models.Person(app.parsePreload("inviter"))});
|
||||
});
|
||||
},
|
||||
|
||||
conversations: function() {
|
||||
app.conversations = new app.views.Conversations();
|
||||
},
|
||||
|
|
@ -134,6 +143,7 @@ app.Router = Backbone.Router.extend({
|
|||
},
|
||||
|
||||
aspects: function() {
|
||||
this._loadAspects();
|
||||
app.aspectSelections = app.aspectSelections ||
|
||||
new app.collections.AspectSelections(app.currentUser.get("aspects"));
|
||||
this.aspectsList = this.aspectsList || new app.views.AspectsList({collection: app.aspectSelections});
|
||||
|
|
@ -157,6 +167,7 @@ app.Router = Backbone.Router.extend({
|
|||
},
|
||||
|
||||
profile: function() {
|
||||
this._loadAspects();
|
||||
this.renderPage(function() {
|
||||
return new app.pages.Profile({
|
||||
el: $("body > #profile_container")
|
||||
|
|
@ -164,6 +175,10 @@ app.Router = Backbone.Router.extend({
|
|||
});
|
||||
},
|
||||
|
||||
_loadAspects: function() {
|
||||
app.aspects = new app.collections.Aspects(app.currentUser.get("aspects"));
|
||||
},
|
||||
|
||||
_hideInactiveStreamLists: function() {
|
||||
if(this.aspectsList && Backbone.history.fragment !== "aspects") {
|
||||
this.aspectsList.hideAspectsList();
|
||||
|
|
|
|||
|
|
@ -9,20 +9,18 @@ app.views.AspectCreate = app.views.Base.extend({
|
|||
},
|
||||
|
||||
initialize: function(opts) {
|
||||
this._personId = _.has(opts, "personId") ? opts.personId : null;
|
||||
if (opts && opts.person) {
|
||||
this.person = opts.person;
|
||||
this._personId = opts.person.id;
|
||||
}
|
||||
},
|
||||
|
||||
presenter: function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
addPersonId: this._personId !== null,
|
||||
personId : this._personId
|
||||
});
|
||||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
this.modal = this.$(".modal");
|
||||
},
|
||||
|
||||
_contactsVisible: function() {
|
||||
return this.$("#aspect_contacts_visible").is(":checked");
|
||||
},
|
||||
|
|
@ -38,28 +36,52 @@ app.views.AspectCreate = app.views.Base.extend({
|
|||
}
|
||||
},
|
||||
|
||||
createAspect: function() {
|
||||
var aspect = new app.models.Aspect({
|
||||
"person_id": this._personId,
|
||||
"name": this._name(),
|
||||
"contacts_visible": this._contactsVisible()
|
||||
postRenderTemplate: function() {
|
||||
this.$(".modal").on("hidden.bs.modal", null, this, function(e) {
|
||||
e.data.ensureEventsOrder();
|
||||
});
|
||||
},
|
||||
|
||||
var self = this;
|
||||
aspect.on("sync", function(response) {
|
||||
var aspectId = response.get("id"),
|
||||
aspectName = response.get("name");
|
||||
createAspect: function() {
|
||||
this._eventsCounter = 0;
|
||||
|
||||
self.modal.modal("hide");
|
||||
app.events.trigger("aspect:create", aspectId);
|
||||
this.$(".modal").modal("hide");
|
||||
|
||||
this.listenToOnce(app.aspects, "sync", function(response) {
|
||||
var aspectName = response.get("name"),
|
||||
membership = response.get("aspect_membership");
|
||||
|
||||
this._newAspectId = response.get("id");
|
||||
|
||||
if (membership) {
|
||||
if (!this.person.contact) {
|
||||
this.person.contact = new app.models.Contact();
|
||||
}
|
||||
this.person.contact.aspectMemberships.add([membership]);
|
||||
}
|
||||
|
||||
this.ensureEventsOrder();
|
||||
app.flashMessages.success(Diaspora.I18n.t("aspects.create.success", {"name": aspectName}));
|
||||
});
|
||||
|
||||
aspect.on("error", function() {
|
||||
self.modal.modal("hide");
|
||||
this.listenToOnce(app.aspects, "error", function() {
|
||||
app.flashMessages.error(Diaspora.I18n.t("aspects.create.failure"));
|
||||
this.stopListening(app.aspects, "sync");
|
||||
});
|
||||
return aspect.save();
|
||||
|
||||
app.aspects.create({
|
||||
"person_id": this._personId || null,
|
||||
"name": this._name(),
|
||||
"contacts_visible": this._contactsVisible()
|
||||
});
|
||||
},
|
||||
|
||||
// ensure that we trigger the aspect:create event only after both hidden.bs.modal and and aspects sync happens
|
||||
ensureEventsOrder: function() {
|
||||
this._eventsCounter++;
|
||||
if (this._eventsCounter > 1) {
|
||||
app.events.trigger("aspect:create", this._newAspectId);
|
||||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//= require ./aspects_dropdown_view
|
||||
|
||||
/**
|
||||
* this view lets the user (de-)select aspect memberships in the context
|
||||
* of another users profile or the contact page.
|
||||
|
|
@ -9,7 +7,13 @@
|
|||
* updates to the list of aspects are immediately propagated to the server, and
|
||||
* the results are dislpayed as flash messages.
|
||||
*/
|
||||
app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
||||
app.views.AspectMembership = app.views.Base.extend({
|
||||
templateName: "aspect_membership_dropdown",
|
||||
className: "btn-group aspect_dropdown aspect_membership_dropdown",
|
||||
|
||||
subviews: {
|
||||
".newAspectContainer": "aspectCreateView"
|
||||
},
|
||||
|
||||
events: {
|
||||
"click ul.aspect_membership.dropdown-menu > li.aspect_selector"
|
||||
|
|
@ -18,70 +22,89 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
: "_clickHandler"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
initialize: function(opts) {
|
||||
_.extend(this, opts);
|
||||
this.list_item = null;
|
||||
this.dropdown = null;
|
||||
if (this.$(".newAspectContainer").length > 0) {
|
||||
this.aspectCreateView = new app.views.AspectCreate({
|
||||
el: this.$(".newAspectContainer"),
|
||||
personId: this.$("ul.dropdown-menu").data("person_id")
|
||||
});
|
||||
this.aspectCreateView.render();
|
||||
}
|
||||
},
|
||||
|
||||
presenter: function() {
|
||||
var aspectMembershipsLength = this.person.contact ? this.person.contact.aspectMemberships.length : 0;
|
||||
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
aspects: this.aspectsPresenter(),
|
||||
dropdownMayCreateNewAspect: this.dropdownMayCreateNewAspect
|
||||
}, aspectMembershipsLength === 0 ? {
|
||||
extraButtonClass: "btn-default",
|
||||
noAspectIsSelected: true
|
||||
} : { // this.contact.aspectMemberships.length > 0
|
||||
aspectMembershipsLength: aspectMembershipsLength,
|
||||
allAspectsAreSelected: aspectMembershipsLength === app.aspects.length,
|
||||
onlyOneAspectIsSelected: aspectMembershipsLength === 1,
|
||||
firstMembershipName: this.person.contact.aspectMemberships.at(0).get("aspect").name,
|
||||
extraButtonClass: "btn-success"
|
||||
});
|
||||
},
|
||||
|
||||
aspectsPresenter: function() {
|
||||
return _.map(app.aspects.models, function(aspect) {
|
||||
return _.extend(
|
||||
this.person.contact ?
|
||||
{membership: this.person.contact.aspectMemberships.findByAspectId(aspect.attributes.id)} : {},
|
||||
aspect.attributes // id, name
|
||||
);
|
||||
}, this);
|
||||
},
|
||||
|
||||
aspectCreateView: function() {
|
||||
return new app.views.AspectCreate({
|
||||
person: this.person
|
||||
});
|
||||
},
|
||||
|
||||
// decide what to do when clicked
|
||||
// -> 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');
|
||||
promise = this.removeMembership(membership_id);
|
||||
if (this.list_item.is(".selected")) {
|
||||
this.removeMembership(this.list_item.data("membership_id"));
|
||||
} else {
|
||||
var aspect_id = this.list_item.data('aspect_id');
|
||||
var person_id = this.dropdown.data('person_id');
|
||||
promise = this.addMembership(person_id, aspect_id);
|
||||
this.addMembership(this.list_item.data("aspect_id"));
|
||||
}
|
||||
|
||||
promise && promise.always(function() {
|
||||
// trigger a global event
|
||||
app.events.trigger('aspect_membership:update');
|
||||
});
|
||||
|
||||
return false; // stop the event
|
||||
},
|
||||
|
||||
// return the (short) name of the person associated with the current dropdown
|
||||
_name: function() {
|
||||
return this.dropdown.data('person-short-name');
|
||||
return this.person.name || this.person.get("name");
|
||||
},
|
||||
|
||||
_personId: function() {
|
||||
return this.person.id;
|
||||
},
|
||||
|
||||
// create a membership for the given person in the given aspect
|
||||
addMembership: function(person_id, aspect_id) {
|
||||
var aspect_membership = new app.models.AspectMembership({
|
||||
'person_id': person_id,
|
||||
'aspect_id': aspect_id
|
||||
addMembership: function(aspectId) {
|
||||
if (!this.person.contact) {
|
||||
this.person.contact = new app.models.Contact();
|
||||
}
|
||||
|
||||
this.listenToOnce(this.person.contact.aspectMemberships, "sync", this._successSaveCb);
|
||||
this.listenToOnce(this.person.contact.aspectMemberships, "error", function() {
|
||||
this._displayError('aspect_dropdown.error');
|
||||
});
|
||||
|
||||
aspect_membership.on('sync', this._successSaveCb, this);
|
||||
aspect_membership.on('error', function() {
|
||||
this._displayError('aspect_dropdown.error');
|
||||
}, this);
|
||||
|
||||
return aspect_membership.save();
|
||||
return this.person.contact.aspectMemberships.create({"aspect_id": aspectId, "person_id": this._personId()});
|
||||
},
|
||||
|
||||
_successSaveCb: function(aspectMembership) {
|
||||
var aspectId = aspectMembership.get("aspect_id"),
|
||||
membershipId = aspectMembership.get("id"),
|
||||
li = this.dropdown.find("li[data-aspect_id='" + aspectId + "']"),
|
||||
personId = li.closest("ul.dropdown-menu").data("person_id"),
|
||||
startSharing = false;
|
||||
|
||||
// the user didn't have this person in any aspects before, congratulate them
|
||||
|
|
@ -93,15 +116,11 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
}
|
||||
|
||||
app.events.trigger("aspect_membership:create", {
|
||||
membership: { aspectId: aspectId, personId: personId },
|
||||
membership: {aspectId: aspectId, personId: this._personId()},
|
||||
startSharing: startSharing
|
||||
});
|
||||
|
||||
li.attr("data-membership_id", membershipId) // just to be sure...
|
||||
.data("membership_id", membershipId);
|
||||
|
||||
this.updateSummary(li);
|
||||
this._done();
|
||||
this.render();
|
||||
app.events.trigger("aspect_membership:update");
|
||||
},
|
||||
|
||||
// show an error flash msg
|
||||
|
|
@ -114,44 +133,35 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
},
|
||||
|
||||
// remove the membership with the given id
|
||||
removeMembership: function(membership_id) {
|
||||
var aspect_membership = new app.models.AspectMembership({
|
||||
'id': membership_id
|
||||
removeMembership: function(membershipId) {
|
||||
var membership = this.person.contact.aspectMemberships.get(membershipId);
|
||||
this.listenToOnce(membership, "sync", this._successDestroyCb);
|
||||
this.listenToOnce(membership, "error", function() {
|
||||
this._displayError("aspect_dropdown.error_remove");
|
||||
});
|
||||
|
||||
aspect_membership.on('sync', this._successDestroyCb, this);
|
||||
aspect_membership.on('error', function() {
|
||||
this._displayError('aspect_dropdown.error_remove');
|
||||
}, this);
|
||||
|
||||
return aspect_membership.destroy();
|
||||
return membership.destroy();
|
||||
},
|
||||
|
||||
_successDestroyCb: function(aspectMembership) {
|
||||
var membershipId = aspectMembership.get("id"),
|
||||
li = this.dropdown.find("li[data-membership_id='" + membershipId + "']"),
|
||||
aspectId = li.data("aspect_id"),
|
||||
personId = li.closest("ul.dropdown-menu").data("person_id"),
|
||||
aspectId = aspectMembership.get("aspect").id,
|
||||
stopSharing = false;
|
||||
|
||||
li.removeAttr("data-membership_id")
|
||||
.removeData("membership_id");
|
||||
this.updateSummary(li);
|
||||
|
||||
this.render();
|
||||
// we just removed the last aspect, inform the user with a flash message
|
||||
// that he is no longer sharing with that person
|
||||
if( this.dropdown.find("li.selected").length === 0 ) {
|
||||
if (this.$el.find("li.selected").length === 0) {
|
||||
var msg = Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", { "name": this._name() });
|
||||
stopSharing = true;
|
||||
app.flashMessages.success(msg);
|
||||
}
|
||||
|
||||
app.events.trigger("aspect_membership:destroy", {
|
||||
membership: { aspectId: aspectId, personId: personId },
|
||||
membership: {aspectId: aspectId, personId: this._personId()},
|
||||
stopSharing: stopSharing
|
||||
});
|
||||
|
||||
this._done();
|
||||
app.events.trigger("aspect_membership:update");
|
||||
},
|
||||
|
||||
// cleanup tasks after aspect selection
|
||||
|
|
@ -160,11 +170,5 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
this.list_item.removeClass('loading');
|
||||
}
|
||||
},
|
||||
|
||||
// refresh the button text to reflect the current aspect selection status
|
||||
updateSummary: function(target) {
|
||||
this._toggleCheckbox(target);
|
||||
this._updateButton("btn-success");
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
app.views.Contact = app.views.Base.extend({
|
||||
templateName: 'contact',
|
||||
|
||||
subviews: {
|
||||
".aspect_membership_dropdown": "AspectMembershipView"
|
||||
},
|
||||
|
||||
events: {
|
||||
"click .contact_add-to-aspect" : "addContactToAspect",
|
||||
"click .contact_remove-from-aspect" : "removeContactFromAspect"
|
||||
|
|
@ -10,6 +14,12 @@ app.views.Contact = app.views.Base.extend({
|
|||
|
||||
tooltipSelector: '.contact_add-to-aspect, .contact_remove-from-aspect',
|
||||
|
||||
initialize: function() {
|
||||
this.AspectMembershipView = new app.views.AspectMembership(
|
||||
{person: _.extend(this.model.get("person"), {contact: this.model})}
|
||||
);
|
||||
},
|
||||
|
||||
presenter: function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
person_id : this.model.get('person_id'),
|
||||
|
|
@ -18,21 +28,6 @@ app.views.Contact = app.views.Base.extend({
|
|||
});
|
||||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
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';
|
||||
|
||||
$.get(href, function(resp) {
|
||||
dropdownEl.html(resp);
|
||||
new app.views.AspectMembership({el: $('.aspect_dropdown',dropdownEl)});
|
||||
});
|
||||
},
|
||||
|
||||
addContactToAspect: function(){
|
||||
var self = this;
|
||||
// do we create the first aspect membership for this person?
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@
|
|||
app.views.ProfileHeader = app.views.Base.extend({
|
||||
templateName: 'profile_header',
|
||||
|
||||
subviews: {
|
||||
".aspect_membership_dropdown": "aspectMembershipView"
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #mention_button": "showMentionModal",
|
||||
"click #message_button": "showMessageModal"
|
||||
},
|
||||
|
||||
initialize: function(opts) {
|
||||
app.events.on('aspect:create', this.postRenderTemplate, this);
|
||||
this.photos = _.has(opts, 'photos') ? opts.photos : null;
|
||||
this.contacts = _.has(opts, 'contacts') ? opts.contacts : null;
|
||||
},
|
||||
|
|
@ -29,6 +32,10 @@ app.views.ProfileHeader = app.views.Base.extend({
|
|||
});
|
||||
},
|
||||
|
||||
aspectMembershipView: function() {
|
||||
return new app.views.AspectMembership({person: this.model, dropdownMayCreateNewAspect: true});
|
||||
},
|
||||
|
||||
_hasTags: function() {
|
||||
return (this.model.get('profile')['tags'].length > 0);
|
||||
},
|
||||
|
|
@ -52,21 +59,6 @@ app.views.ProfileHeader = app.views.Base.extend({
|
|||
showMessageModal: function(){
|
||||
app.helpers.showModal("#conversationModal");
|
||||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
var dropdownEl = this.$('.aspect_membership_dropdown.placeholder');
|
||||
if( dropdownEl.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO render me client side!!!
|
||||
var href = this.model.url() + '/aspect_membership_button?create=true&size=normal';
|
||||
|
||||
$.get(href, function(resp) {
|
||||
dropdownEl.html(resp);
|
||||
new app.views.AspectMembership({el: $('.aspect_dropdown',dropdownEl)});
|
||||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -120,3 +120,21 @@ $default-border-radius: 3px;
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin selectable-list() {
|
||||
.glyphicon-ok,
|
||||
.glyphicon-refresh {
|
||||
display: none;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
.glyphicon-ok { display: inline-block;}
|
||||
.glyphicon-refresh { display: none;}
|
||||
}
|
||||
|
||||
&.loading {
|
||||
.glyphicon-refresh { display: inline-block;}
|
||||
.glyphicon-ok { display: none;}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,14 @@
|
|||
.aspect_dropdown {
|
||||
|
||||
li {
|
||||
@include selectable-list;
|
||||
|
||||
.status_indicator {
|
||||
width: 19px;
|
||||
height: 14px;
|
||||
display: inline-block;
|
||||
}
|
||||
.glyphicon-ok, .icon-refresh {
|
||||
padding-right: 5px;
|
||||
display: none;
|
||||
}
|
||||
&.selected {
|
||||
.glyphicon-ok { display: inline-block;}
|
||||
.icon-refresh { display: none;}
|
||||
}
|
||||
&.loading {
|
||||
.icon-refresh { display: inline-block;}
|
||||
.glyphicon-ok { display: none;}
|
||||
}
|
||||
|
||||
a {
|
||||
.text {
|
||||
color: #333333;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<div class="modal-body">
|
||||
<form>
|
||||
<fieldset>
|
||||
{{#if addPersonId}}
|
||||
{{#if personId}}
|
||||
<input id="aspect_person_id" type="hidden" value="{{ personId }}">
|
||||
{{/if}}
|
||||
|
||||
|
|
|
|||
52
app/assets/templates/aspect_membership_dropdown_tpl.jst.hbs
Normal file
52
app/assets/templates/aspect_membership_dropdown_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<button class="btn dropdown-toggle {{extraButtonClass}}" data-toggle="dropdown" tabindex="0">
|
||||
<span class="text">
|
||||
{{#if allAspectsAreSelected }}
|
||||
{{ t "aspect_dropdown.all_aspects" }}
|
||||
{{else if onlyOneAspectIsSelected}}
|
||||
{{ firstMembershipName }}
|
||||
{{else if noAspectIsSelected}}
|
||||
{{ t "aspect_dropdown.add_to_aspect"}}
|
||||
{{else}}
|
||||
{{ t "aspect_dropdown.toggle" count=aspectMembershipsLength }}
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class="caret" />
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu aspect_membership pull-right" unselectable="on">
|
||||
{{#each aspects}}
|
||||
<li
|
||||
{{#if membership}}
|
||||
class="aspect_selector selected"
|
||||
{{else}}
|
||||
class="aspect_selector"
|
||||
{{/if}}
|
||||
|
||||
data-aspect_id="{{id}}"
|
||||
{{#if membership}}
|
||||
data-membership_id="{{membership.id}}"
|
||||
{{/if}}
|
||||
>
|
||||
<a>
|
||||
<span class="status_indicator">
|
||||
<i class="glyphicon glyphicon-ok" />
|
||||
<i class="glyphicon glyphicon-refresh" />
|
||||
</span>
|
||||
<span class="text">
|
||||
{{name}}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{#if dropdownMayCreateNewAspect}}
|
||||
<li class="divider" />
|
||||
<li class="newItem add_aspect">
|
||||
<a data-target="#newAspectModal" data-toggle="modal" href="#">
|
||||
{{ t "aspects.create.add_a_new_aspect" }}
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
{{#if dropdownMayCreateNewAspect}}
|
||||
<div class="newAspectContainer"/>
|
||||
{{/if}}
|
||||
|
|
@ -14,10 +14,13 @@ class AspectsController < ApplicationController
|
|||
aspecting_person_id = params[:person_id]
|
||||
|
||||
if @aspect.save
|
||||
result = {id: @aspect.id, name: @aspect.name}
|
||||
if aspecting_person_id.present?
|
||||
connect_person_to_aspect(aspecting_person_id)
|
||||
aspect_membership = connect_person_to_aspect(aspecting_person_id)
|
||||
result[:aspect_membership] = AspectMembershipPresenter.new(aspect_membership).base_hash if aspect_membership
|
||||
end
|
||||
render json: {id: @aspect.id, name: @aspect.name}
|
||||
|
||||
render json: result
|
||||
else
|
||||
render nothing: true, status: 422
|
||||
end
|
||||
|
|
@ -96,9 +99,10 @@ class AspectsController < ApplicationController
|
|||
def connect_person_to_aspect(aspecting_person_id)
|
||||
@person = Person.find(aspecting_person_id)
|
||||
if @contact = current_user.contact_for(@person)
|
||||
@contact.aspects << @aspect
|
||||
@contact.aspect_memberships.create(aspect: @aspect)
|
||||
else
|
||||
@contact = current_user.share_with(@person, @aspect)
|
||||
@contact.aspect_memberships.first
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -146,21 +146,6 @@ class PeopleController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# shows the dropdown list of aspects the current user has set for the given person.
|
||||
# renders "thats you" in case the current user views himself
|
||||
def aspect_membership_dropdown
|
||||
@person = Person.find_by_guid(params[:person_id])
|
||||
|
||||
# you are not a contact of yourself...
|
||||
return render :text => I18n.t('people.person.thats_you') if @person == current_user.person
|
||||
|
||||
@contact = current_user.contact_for(@person) || Contact.new
|
||||
@aspect = :profile if params[:create] # let aspect dropdown create new aspects
|
||||
size = params[:size] || "small"
|
||||
|
||||
render :partial => 'aspect_membership_dropdown', :locals => {:contact => @contact, :person => @person, :hang => 'left', :size => size}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_person
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ class UsersController < ApplicationController
|
|||
@user = current_user
|
||||
@person = @user.person
|
||||
@profile = @user.profile
|
||||
gon.preloads[:inviter] = PersonPresenter.new(current_user.invited_by.try(:person), current_user).as_json
|
||||
|
||||
render "users/getting_started"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# the COPYRIGHT file.
|
||||
|
||||
module AspectGlobalHelper
|
||||
def aspect_membership_dropdown(contact, person, hang, aspect=nil, size="small")
|
||||
def aspect_membership_dropdown(contact, person, hang)
|
||||
aspect_membership_ids = {}
|
||||
|
||||
selected_aspects = all_aspects.select{|aspect| contact.in_aspect?(aspect)}
|
||||
|
|
@ -13,41 +13,15 @@ module AspectGlobalHelper
|
|||
end
|
||||
|
||||
button_class = selected_aspects.size > 0 ? "btn-success" : "btn-default"
|
||||
button_class << case size
|
||||
when "small"
|
||||
" btn-small"
|
||||
when "normal"
|
||||
""
|
||||
when "large"
|
||||
" btn-large"
|
||||
else
|
||||
raise ArgumentError, "unknown size #{size}"
|
||||
end
|
||||
|
||||
render "aspect_memberships/aspect_membership_dropdown",
|
||||
:selected_aspects => selected_aspects,
|
||||
:aspect_membership_ids => aspect_membership_ids,
|
||||
:person => person,
|
||||
:hang => hang,
|
||||
:dropdown_class => "aspect_membership",
|
||||
:button_class => button_class
|
||||
end
|
||||
|
||||
def aspect_dropdown_list_item(aspect, am_id=nil)
|
||||
klass = am_id.present? ? "selected" : ""
|
||||
|
||||
str = <<LISTITEM
|
||||
<li data-aspect_id="#{aspect.id}" data-membership_id="#{am_id}" class="#{klass} aspect_selector" tabindex="0">
|
||||
#{aspect.name}
|
||||
</li>
|
||||
LISTITEM
|
||||
str.html_safe
|
||||
end
|
||||
|
||||
def dropdown_may_create_new_aspect
|
||||
@aspect == :profile || @aspect == :tag || @aspect == :notification || params[:action] == "getting_started"
|
||||
end
|
||||
|
||||
def aspect_options_for_select(aspects)
|
||||
options = {}
|
||||
aspects.each do |aspect|
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@ class ContactPresenter < BasePresenter
|
|||
end
|
||||
|
||||
def full_hash_with_person
|
||||
full_hash.merge(person: PersonPresenter.new(person, current_user).as_json)
|
||||
full_hash.merge(person: person_without_contact)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def person_without_contact
|
||||
PersonPresenter.new(person, current_user).as_json.except!(:contact)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class PersonPresenter < BasePresenter
|
|||
base_hash.merge(
|
||||
relationship: relationship,
|
||||
block: is_blocked? ? BlockPresenter.new(current_user_person_block).base_hash : false,
|
||||
contact: (!own_profile? && has_contact?) ? {id: current_user_person_contact.id} : false,
|
||||
contact: (!own_profile? && has_contact?) ? contact_hash : false,
|
||||
is_own_profile: own_profile?,
|
||||
show_profile_info: public_details? || own_profile? || person_is_following_current_user
|
||||
)
|
||||
|
|
@ -58,6 +58,10 @@ class PersonPresenter < BasePresenter
|
|||
attrs
|
||||
end
|
||||
|
||||
def contact_hash
|
||||
ContactPresenter.new(current_user_person_contact).full_hash
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user_person_block
|
||||
|
|
|
|||
|
|
@ -1,30 +1 @@
|
|||
.btn-group.aspect_dropdown.aspect_membership_dropdown
|
||||
%button.btn.dropdown-toggle{:class => button_class, "data-toggle" => "dropdown", :tabindex => '0'}
|
||||
%span.text
|
||||
- if selected_aspects.size == all_aspects.size
|
||||
= t('all_aspects')
|
||||
- elsif selected_aspects.size == 1
|
||||
= selected_aspects.first.name
|
||||
- else
|
||||
= t('shared.aspect_dropdown.toggle', :count => selected_aspects.size)
|
||||
%span.caret
|
||||
|
||||
%ul.dropdown-menu{:class => ["pull-#{hang}", defined?(dropdown_class) && dropdown_class], :unSelectable => 'on', 'data-person_id' => (person.id if defined?(person) && person), 'data-service_uid' => (service_uid if defined?(service_uid)), 'data-person-short-name' => (person.first_name if defined?(person) && person)}
|
||||
- for aspect in all_aspects
|
||||
%li.aspect_selector{ :class => ('selected' if aspect_membership_ids[aspect.id].present?), 'data-aspect_id' => aspect.id, 'data-membership_id' => aspect_membership_ids[aspect.id], :tabindex => '0' }
|
||||
%a
|
||||
%span.status_indicator
|
||||
%i.glyphicon.glyphicon-ok
|
||||
%i.icon-refresh
|
||||
%span.text
|
||||
= aspect.name
|
||||
|
||||
- if dropdown_may_create_new_aspect && defined?(person) && person
|
||||
%li.divider
|
||||
%li.newItem.add_aspect
|
||||
%a{ href: "#", data: { toggle: "modal", target: "#newAspectModal" }}
|
||||
= t("contacts.index.add_a_new_aspect")
|
||||
|
||||
- if dropdown_may_create_new_aspect && defined?(person) && person
|
||||
.newAspectContainer
|
||||
-# JS
|
||||
.placeholder.aspect_membership_dropdown
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
= t('.invited_by')
|
||||
.media
|
||||
.pull-right
|
||||
= aspect_membership_dropdown(contact, inviter, false)
|
||||
= render partial: "aspect_memberships/aspect_membership_dropdown", locals: {person: inviter}
|
||||
.media-left
|
||||
= person_image_link(inviter, size: :thumb_small, class: "media-object")
|
||||
.media-body
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
= aspect_membership_dropdown(@contact, @person, 'right', nil, size)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
- unless person == current_user.person
|
||||
- contact = current_user.contacts.find_by_person_id(person.id)
|
||||
- contact ||= Contact.new(:person => person)
|
||||
= aspect_membership_dropdown(contact, person, 'right')
|
||||
.aspect_membership_dropdown
|
||||
-else
|
||||
%span.thats_you
|
||||
= t('people.person.thats_you')
|
||||
|
|
|
|||
|
|
@ -1024,7 +1024,6 @@ en:
|
|||
mobile_row_checked: "%{name} (remove)"
|
||||
mobile_row_unchecked: "%{name} (add)"
|
||||
toggle:
|
||||
zero: "Add contact"
|
||||
one: "In %{count} aspect"
|
||||
other: "In %{count} aspects"
|
||||
publisher:
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ en:
|
|||
error: "Couldn’t start sharing with <%= name %>. Are you ignoring them?"
|
||||
error_remove: "Couldn’t remove <%= name %> from the aspect :("
|
||||
toggle:
|
||||
zero: "Select aspects"
|
||||
one: "In <%= count %> aspect"
|
||||
other: "In <%= count %> aspects"
|
||||
show_more: "Show more"
|
||||
|
|
|
|||
|
|
@ -169,7 +169,6 @@ Diaspora::Application.routes.draw do
|
|||
resources :status_messages
|
||||
resources :photos
|
||||
get :contacts
|
||||
get "aspect_membership_button" => :aspect_membership_dropdown, :as => "aspect_membership_button"
|
||||
get :stream
|
||||
get :hovercard
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Feature: following and being followed
|
|||
And I go to the edit profile page
|
||||
And I fill in the following:
|
||||
| profile_first_name | <script>alert(0)// |
|
||||
| profile_last_name ||
|
||||
And I press "update_profile"
|
||||
Then I should be on my edit profile page
|
||||
|
||||
|
|
|
|||
|
|
@ -20,17 +20,4 @@ describe PeopleController, :type => :controller do
|
|||
save_fixture(html_for("body"), "pending_external_people_search")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#aspect_membership_dropdown' do
|
||||
before do
|
||||
aspect = bob.aspects.create name: 'Testing'
|
||||
bob.share_with alice.person, aspect
|
||||
sign_in :user, bob
|
||||
end
|
||||
|
||||
it "generates a jasmine fixture", :fixture => true do
|
||||
get :aspect_membership_dropdown, :person_id => alice.person.guid
|
||||
save_fixture(html_for("body"), "aspect_membership_dropdown")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
19
spec/controllers/jasmine_fixtures/users_spec.rb
Normal file
19
spec/controllers/jasmine_fixtures/users_spec.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe UsersController, type: :controller do
|
||||
before do
|
||||
sign_in :user, alice
|
||||
end
|
||||
|
||||
describe "#getting_started" do
|
||||
before do
|
||||
alice.invited_by = bob
|
||||
alice.save!
|
||||
end
|
||||
|
||||
it "generates a jasmine fixture with no query", fixture: true do
|
||||
get :getting_started
|
||||
save_fixture(html_for("body"), "getting_started")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe PeopleController, :type => :controller do
|
||||
include_context :gon
|
||||
|
||||
before do
|
||||
@user = alice
|
||||
@aspect = @user.aspects.first
|
||||
|
|
@ -277,6 +279,11 @@ describe PeopleController, :type => :controller do
|
|||
get :show, id: @person.to_param
|
||||
expect(response.body).to include(@person.profile.bio)
|
||||
end
|
||||
|
||||
it "preloads data using gon for the aspect memberships dropdown" do
|
||||
get :show, id: @person.to_param
|
||||
expect_gon_preloads_for_aspect_membership_dropdown(:person, true)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the person is not a contact of the current user" do
|
||||
|
|
@ -298,6 +305,11 @@ describe PeopleController, :type => :controller do
|
|||
get :show, id: @person.to_param
|
||||
expect(response.body).not_to include(@person.profile.bio)
|
||||
end
|
||||
|
||||
it "preloads data using gon for the aspect memberships dropdown" do
|
||||
get :show, id: @person.to_param
|
||||
expect_gon_preloads_for_aspect_membership_dropdown(:person, false)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the user is following the person" do
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe UsersController, :type => :controller do
|
||||
include_context :gon
|
||||
|
||||
before do
|
||||
@user = alice
|
||||
sign_in :user, @user
|
||||
|
|
@ -319,5 +321,19 @@ describe UsersController, :type => :controller do
|
|||
get :getting_started, :format => :mobile
|
||||
expect(response).to be_success
|
||||
end
|
||||
|
||||
context "with inviter" do
|
||||
[bob, eve].each do |inviter|
|
||||
sharing = !alice.contact_for(inviter.person).nil?
|
||||
|
||||
context sharing ? "when sharing" : "when don't share" do
|
||||
it "preloads data using gon for the aspect memberships dropdown" do
|
||||
alice.invited_by = inviter
|
||||
get :getting_started
|
||||
expect_gon_preloads_for_aspect_membership_dropdown(:inviter, sharing)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
17
spec/javascripts/app/collections/aspect_memberships_spec.js
Normal file
17
spec/javascripts/app/collections/aspect_memberships_spec.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
describe("app.collections.AspectMemberships", function() {
|
||||
beforeEach(function() {
|
||||
this.models = [factory.aspectMembershipAttrs(), factory.aspectMembershipAttrs(), factory.aspectMembershipAttrs()];
|
||||
this.collection = new app.collections.AspectMemberships(this.models);
|
||||
});
|
||||
|
||||
describe("#findByAspectId", function() {
|
||||
it("finds a model in collection", function() {
|
||||
var model = this.collection.findByAspectId(this.models[1].aspect.id);
|
||||
expect(model.get("id")).toEqual(this.models[1].id);
|
||||
});
|
||||
|
||||
it("returns undefined when nothing found", function() {
|
||||
expect(this.collection.findByAspectId(factory.id.next())).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -8,6 +8,13 @@ describe("app.models.Contact", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("initialize", function() {
|
||||
it("sets person object with contact reference", function() {
|
||||
expect(this.contact.person.get("name")).toEqual("aaa");
|
||||
expect(this.contact.person.contact).toEqual(this.contact);
|
||||
});
|
||||
});
|
||||
|
||||
describe("inAspect", function(){
|
||||
it("returns true if the contact has been added to the aspect", function(){
|
||||
expect(this.contact.inAspect(this.aspect.id)).toBeTruthy();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@ describe("app.models.Person", function() {
|
|||
this.blockedContact = factory.person({relationship: "blocked", block: {id: 1}});
|
||||
});
|
||||
|
||||
describe("initialize", function() {
|
||||
it("sets contact object with person reference", function() {
|
||||
var contact = {id: factory.id.next()};
|
||||
var person = factory.person({contact: contact});
|
||||
expect(person.contact.get("id")).toEqual(contact.id);
|
||||
expect(person.contact.person).toEqual(person);
|
||||
});
|
||||
});
|
||||
|
||||
context("#isSharing", function() {
|
||||
it("indicates if the person is sharing", function() {
|
||||
expect(this.mutualContact.isSharing()).toBeTruthy();
|
||||
|
|
|
|||
15
spec/javascripts/app/pages/getting_started_spec.js
Normal file
15
spec/javascripts/app/pages/getting_started_spec.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
describe("app.pages.GettingStarted", function() {
|
||||
beforeEach(function() {
|
||||
spec.loadFixture("getting_started");
|
||||
app.aspects = new app.collections.Aspects([factory.aspect()]);
|
||||
|
||||
this.view = new app.pages.GettingStarted({
|
||||
inviter: factory.person()
|
||||
});
|
||||
});
|
||||
|
||||
it("renders aspect membership dropdown", function() {
|
||||
this.view.render();
|
||||
expect($("ul.dropdown-menu.aspect_membership").length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
|
@ -88,6 +88,13 @@ describe('app.Router', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("gettingStarted", function() {
|
||||
it("renders app.pages.GettingStarted", function() {
|
||||
app.router.navigate("/getting_started", {trigger: true});
|
||||
expect(app.page.$el.selector).toEqual("#hello-there");
|
||||
});
|
||||
});
|
||||
|
||||
describe("_initializeStreamView", function() {
|
||||
beforeEach(function() {
|
||||
delete app.page;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ describe("app.views.AspectCreate", function() {
|
|||
app.events.off("aspect:create");
|
||||
});
|
||||
|
||||
context("without a person id", function() {
|
||||
context("without a person", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.AspectCreate();
|
||||
});
|
||||
|
|
@ -50,6 +50,7 @@ describe("app.views.AspectCreate", function() {
|
|||
this.view.render();
|
||||
this.view.$el.append($("<div id='flash-container'/>"));
|
||||
app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
|
||||
app.aspects = new app.collections.Aspects();
|
||||
});
|
||||
|
||||
it("should send the correct name to the server", function() {
|
||||
|
|
@ -134,9 +135,10 @@ describe("app.views.AspectCreate", function() {
|
|||
});
|
||||
});
|
||||
|
||||
context("with a person id", function() {
|
||||
context("with a person", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.AspectCreate({personId: "42"});
|
||||
var person = new app.models.Person({id: "42"});
|
||||
this.view = new app.views.AspectCreate({person: person});
|
||||
});
|
||||
|
||||
describe("#render", function() {
|
||||
|
|
@ -161,6 +163,7 @@ describe("app.views.AspectCreate", function() {
|
|||
describe("#createAspect", function() {
|
||||
beforeEach(function() {
|
||||
this.view.render();
|
||||
app.aspects = new app.collections.Aspects();
|
||||
});
|
||||
|
||||
it("should send the correct name to the server", function() {
|
||||
|
|
@ -193,6 +196,36 @@ describe("app.views.AspectCreate", function() {
|
|||
expect(obj.person_id).toBe("42");
|
||||
/* jshint camelcase: true */
|
||||
});
|
||||
|
||||
it("should ensure that events order is fine", function() {
|
||||
spyOn(this.view, "ensureEventsOrder").and.callThrough();
|
||||
this.view.$(".modal").removeClass("fade");
|
||||
this.view.$(".modal").modal("toggle");
|
||||
this.view.createAspect();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
responseText: JSON.stringify({id: 1337, name: "new name"})
|
||||
});
|
||||
expect(this.view.ensureEventsOrder.calls.count()).toBe(2);
|
||||
});
|
||||
|
||||
it("should ensure that events order is fine after failure", function() {
|
||||
spyOn(this.view, "ensureEventsOrder").and.callThrough();
|
||||
this.view.$(".modal").removeClass("fade");
|
||||
this.view.$(".modal").modal("toggle");
|
||||
this.view.createAspect();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status: 422});
|
||||
expect(this.view.ensureEventsOrder.calls.count()).toBe(1);
|
||||
|
||||
this.view.$(".modal").removeClass("fade");
|
||||
this.view.$(".modal").modal("toggle");
|
||||
this.view.createAspect();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
responseText: JSON.stringify({id: 1337, name: "new name"})
|
||||
});
|
||||
expect(this.view.ensureEventsOrder.calls.count()).toBe(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,45 +3,53 @@ describe("app.views.AspectMembership", function(){
|
|||
var resp_fail = {status: 400};
|
||||
|
||||
beforeEach(function() {
|
||||
// mock a dummy aspect dropdown
|
||||
spec.loadFixture("aspect_membership_dropdown");
|
||||
this.view = new app.views.AspectMembership({el: $('.aspect_membership_dropdown')});
|
||||
this.view.$el.append($("<div id='flash-container'/>"));
|
||||
app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
|
||||
this.personId = $(".dropdown-menu").data("person_id");
|
||||
this.personName = $(".dropdown-menu").data("person-short-name");
|
||||
var contact = factory.contact();
|
||||
this.person = contact.person;
|
||||
this.personName = this.person.get("name");
|
||||
var aspectAttrs = contact.aspectMemberships.at(0).get("aspect");
|
||||
app.aspects = new app.collections.Aspects([factory.aspect(aspectAttrs), factory.aspect()]);
|
||||
this.view = new app.views.AspectMembership({person: this.person});
|
||||
this.view.render();
|
||||
spec.content().append($("<div id='flash-container'/>"));
|
||||
app.flashMessages = new app.views.FlashMessages({el: spec.content().find("#flash-container")});
|
||||
});
|
||||
|
||||
context('adding to aspects', function() {
|
||||
beforeEach(function() {
|
||||
this.newAspect = $('li:not(.selected)');
|
||||
this.newAspect = this.view.$("li:not(.selected)");
|
||||
this.newAspectId = this.newAspect.data('aspect_id');
|
||||
});
|
||||
|
||||
it('marks the aspect as selected', function() {
|
||||
this.newAspect.trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(success);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
responseText: JSON.stringify({
|
||||
id: factory.id.next(),
|
||||
aspect: app.aspects.at(1).attributes
|
||||
})
|
||||
});
|
||||
|
||||
expect(this.newAspect.attr('class')).toContain('selected');
|
||||
expect(this.view.$("li[data-aspect_id=" + this.newAspectId + "]").attr("class")).toContain("selected");
|
||||
});
|
||||
|
||||
it('displays flash message when added to first aspect', function() {
|
||||
spec.content().find('li').removeClass('selected');
|
||||
this.view.$("li").removeClass("selected");
|
||||
this.newAspect.trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(success);
|
||||
|
||||
expect(this.view.$(".flash-message")).toBeSuccessFlashMessage(
|
||||
expect(spec.content().find(".flash-message")).toBeSuccessFlashMessage(
|
||||
Diaspora.I18n.t("aspect_dropdown.started_sharing_with", {name: this.personName})
|
||||
);
|
||||
});
|
||||
|
||||
it("triggers aspect_membership:create", function() {
|
||||
spyOn(app.events, "trigger");
|
||||
spec.content().find("li").removeClass("selected");
|
||||
this.view.$("li").removeClass("selected");
|
||||
this.newAspect.trigger("click");
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(success);
|
||||
expect(app.events.trigger).toHaveBeenCalledWith("aspect_membership:create", {
|
||||
membership: {aspectId: this.newAspectId, personId: this.personId},
|
||||
membership: {aspectId: this.newAspectId, personId: this.person.id},
|
||||
startSharing: true
|
||||
});
|
||||
});
|
||||
|
|
@ -50,7 +58,7 @@ describe("app.views.AspectMembership", function(){
|
|||
this.newAspect.trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(resp_fail);
|
||||
|
||||
expect(this.view.$(".flash-message")).toBeErrorFlashMessage(
|
||||
expect(spec.content().find(".flash-message")).toBeErrorFlashMessage(
|
||||
Diaspora.I18n.t("aspect_dropdown.error", {name: this.personName})
|
||||
);
|
||||
});
|
||||
|
|
@ -58,34 +66,32 @@ describe("app.views.AspectMembership", function(){
|
|||
|
||||
context('removing from aspects', function(){
|
||||
beforeEach(function() {
|
||||
this.oldAspect = $('li.selected').first();
|
||||
this.oldMembershipId = this.oldAspect.data('membership_id');
|
||||
this.oldAspect = this.view.$("li.selected").first();
|
||||
this.oldAspectId = this.oldAspect.data("aspect_id");
|
||||
});
|
||||
|
||||
it('marks the aspect as unselected', function(){
|
||||
this.oldAspect.trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(success);
|
||||
|
||||
expect(this.oldAspect.attr('class')).not.toContain('selected');
|
||||
expect(this.view.$("li[data-aspect_id=" + this.oldAspectId + "]").attr("class")).not.toContain("selected");
|
||||
});
|
||||
|
||||
it('displays a flash message when removed from last aspect', function() {
|
||||
spec.content().find('li.selected:last').removeClass('selected');
|
||||
this.oldAspect.trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(success);
|
||||
|
||||
expect(this.view.$(".flash-message")).toBeSuccessFlashMessage(
|
||||
expect(spec.content().find(".flash-message")).toBeSuccessFlashMessage(
|
||||
Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", {name: this.personName})
|
||||
);
|
||||
});
|
||||
|
||||
it("triggers aspect_membership:destroy", function() {
|
||||
spyOn(app.events, "trigger");
|
||||
spec.content().find("li.selected:last").removeClass("selected");
|
||||
this.oldAspect.trigger("click");
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(success);
|
||||
expect(app.events.trigger).toHaveBeenCalledWith("aspect_membership:destroy", {
|
||||
membership: {aspectId: this.oldAspect.data("aspect_id"), personId: this.personId},
|
||||
membership: {aspectId: this.oldAspectId, personId: this.person.id},
|
||||
stopSharing: true
|
||||
});
|
||||
});
|
||||
|
|
@ -94,29 +100,9 @@ describe("app.views.AspectMembership", function(){
|
|||
this.oldAspect.trigger('click');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith(resp_fail);
|
||||
|
||||
expect(this.view.$(".flash-message")).toBeErrorFlashMessage(
|
||||
expect(spec.content().find(".flash-message")).toBeErrorFlashMessage(
|
||||
Diaspora.I18n.t("aspect_dropdown.error_remove", {name: this.personName})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('button summary text', function() {
|
||||
beforeEach(function() {
|
||||
this.Aspect = $('li:eq(0)');
|
||||
});
|
||||
|
||||
it('calls "_toggleCheckbox"', function() {
|
||||
spyOn(this.view, "_toggleCheckbox");
|
||||
this.view.updateSummary(this.Aspect);
|
||||
|
||||
expect(this.view._toggleCheckbox).toHaveBeenCalledWith(this.Aspect);
|
||||
});
|
||||
|
||||
it('calls "_updateButton"', function() {
|
||||
spyOn(this.view, "_updateButton");
|
||||
this.view.updateSummary(this.Aspect);
|
||||
|
||||
expect(this.view._updateButton).toHaveBeenCalledWith("btn-success");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,16 @@ var factory = {
|
|||
return _.extend(defaultAttrs, overrides);
|
||||
},
|
||||
|
||||
aspectMembershipAttrs: function(overrides) {
|
||||
var id = this.id.next();
|
||||
var defaultAttrs = {
|
||||
"id": id,
|
||||
"aspect": factory.aspectAttrs()
|
||||
};
|
||||
|
||||
return _.extend(defaultAttrs, overrides);
|
||||
},
|
||||
|
||||
comment : function(overrides) {
|
||||
var defaultAttrs = {
|
||||
"created_at" : "2012-01-04T00:55:30Z",
|
||||
|
|
@ -33,6 +43,18 @@ var factory = {
|
|||
return new app.models.Comment(_.extend(defaultAttrs, overrides));
|
||||
},
|
||||
|
||||
contact: function(overrides) {
|
||||
var person = factory.personAttrs();
|
||||
var attrs = {
|
||||
"id": this.id.next(),
|
||||
"person_id": person.id,
|
||||
"person": person,
|
||||
"aspect_memberships": factory.aspectMembershipAttrs()
|
||||
};
|
||||
|
||||
return new app.models.Contact(_.extend(attrs, overrides));
|
||||
},
|
||||
|
||||
user : function(overrides) {
|
||||
return new app.models.User(factory.userAttrs(overrides));
|
||||
},
|
||||
|
|
@ -189,6 +211,7 @@ var factory = {
|
|||
aspectAttrs: function(overrides) {
|
||||
var names = ['Work','School','Family','Friends','Just following','People','Interesting'];
|
||||
var defaultAttrs = {
|
||||
id: this.id.next(),
|
||||
name: names[Math.floor(Math.random()*names.length)]+' '+Math.floor(Math.random()*100),
|
||||
selected: false
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,5 +25,13 @@ describe ContactPresenter do
|
|||
it "has relationship information" do
|
||||
expect(@presenter.full_hash_with_person[:person][:relationship]).to be(:mutual)
|
||||
end
|
||||
|
||||
it "doesn't have redundant contact object in person hash" do
|
||||
expect(@presenter.full_hash_with_person[:person]).not_to have_key(:contact)
|
||||
end
|
||||
|
||||
it "has avatar links in person profile hash" do
|
||||
expect(@presenter.full_hash_with_person[:person][:profile]).to have_key(:avatar)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
30
spec/support/gon.rb
Normal file
30
spec/support/gon.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
shared_context :gon do
|
||||
let(:gon) { RequestStore.store[:gon].gon }
|
||||
end
|
||||
|
||||
module HelperMethods
|
||||
def expect_aspects
|
||||
expect(gon["user"].aspects).not_to be_nil
|
||||
expect(gon["user"].aspects.length).not_to be_nil
|
||||
end
|
||||
|
||||
def expect_memberships(memberships)
|
||||
expect(memberships).not_to be_nil
|
||||
expect(memberships.length).not_to be_nil
|
||||
end
|
||||
|
||||
def expect_contact(preload_key)
|
||||
expect(gon["preloads"][preload_key][:contact]).not_to be_falsy
|
||||
expect_memberships(gon["preloads"][preload_key][:contact][:aspect_memberships])
|
||||
end
|
||||
|
||||
def expect_gon_preloads_for_aspect_membership_dropdown(preload_key, sharing)
|
||||
expect(gon["preloads"][preload_key]).not_to be_nil
|
||||
if sharing
|
||||
expect_contact(preload_key)
|
||||
else
|
||||
expect(gon["preloads"][preload_key][:contact]).to be_falsy
|
||||
end
|
||||
expect_aspects
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue