Refactor contacts page using pagination
This commit is contained in:
parent
d022e51a0c
commit
993f3d5ab0
11 changed files with 374 additions and 168 deletions
|
|
@ -8,7 +8,6 @@ app.pages.Contacts = Backbone.View.extend({
|
|||
"click #contacts_visibility_toggle" : "toggleContactVisibility",
|
||||
"click #chat_privilege_toggle" : "toggleChatPrivilege",
|
||||
"click #change_aspect_name" : "showAspectNameForm",
|
||||
"keyup #contact_list_search" : "searchContactList",
|
||||
"click .conversation_button": "showMessageModal",
|
||||
"click #invitations-button": "showInvitationsModal"
|
||||
},
|
||||
|
|
@ -79,10 +78,6 @@ app.pages.Contacts = Backbone.View.extend({
|
|||
$(".header > h3").show();
|
||||
},
|
||||
|
||||
searchContactList: function(e) {
|
||||
this.stream.search($(e.target).val());
|
||||
},
|
||||
|
||||
showMessageModal: function(){
|
||||
app.helpers.showModal("#conversationModal");
|
||||
},
|
||||
|
|
|
|||
|
|
@ -81,13 +81,14 @@ app.Router = Backbone.Router.extend({
|
|||
).render();
|
||||
},
|
||||
|
||||
contacts: function() {
|
||||
contacts: function(params) {
|
||||
app.aspect = new app.models.Aspect(gon.preloads.aspect);
|
||||
this._loadContacts();
|
||||
|
||||
var stream = new app.views.ContactStream({
|
||||
collection: app.contacts,
|
||||
el: $(".stream.contacts #contact_stream")
|
||||
el: $(".stream.contacts #contact_stream"),
|
||||
urlParams: params
|
||||
});
|
||||
|
||||
app.page = new app.pages.Contacts({stream: stream});
|
||||
|
|
|
|||
|
|
@ -1,77 +1,79 @@
|
|||
// @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();
|
||||
initialize: function(opts) {
|
||||
this.page = 1;
|
||||
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
|
||||
$(window).scroll(throttledScroll);
|
||||
this.on('renderContacts', this.renderContacts, this);
|
||||
this.on("fetchContacts", this.fetchContacts, this);
|
||||
this.urlParams = opts.urlParams;
|
||||
},
|
||||
|
||||
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();
|
||||
}
|
||||
this.fetchContacts();
|
||||
},
|
||||
|
||||
renderContacts: function() {
|
||||
fetchContacts: 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);
|
||||
$("#paginate .loader").removeClass("hidden");
|
||||
$.ajax(this._fetchUrl(), {
|
||||
context: this
|
||||
}).success(function(response) {
|
||||
if (response.length === 0) {
|
||||
this.onEmptyResponse();
|
||||
} else {
|
||||
this.appendContactViews(response);
|
||||
this.page++;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
var size = _.size(this.resultList);
|
||||
if( this.itemCount + this.perPage >= size ){
|
||||
this.itemCount = size;
|
||||
this.off('renderContacts');
|
||||
} else {
|
||||
this.itemCount += this.perPage;
|
||||
_fetchUrl: function() {
|
||||
var url = Routes.contacts({format: "json", page: this.page});
|
||||
if (this.urlParams) {
|
||||
url += "&" + this.urlParams;
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
onEmptyResponse: function() {
|
||||
if (this.collection.length === 0) {
|
||||
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);
|
||||
}
|
||||
this.off("fetchContacts");
|
||||
this.$el.removeClass("loading");
|
||||
$("#paginate .loader").addClass("hidden");
|
||||
},
|
||||
|
||||
appendContactViews: function(contacts) {
|
||||
var content = document.createDocumentFragment();
|
||||
contacts.forEach(function(contactData) {
|
||||
var contact = new app.models.Contact(contactData);
|
||||
this.collection.add(contact);
|
||||
var view = new app.views.Contact({model: contact});
|
||||
content.appendChild(view.render().el);
|
||||
}.bind(this));
|
||||
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();
|
||||
}
|
||||
$("#paginate .loader").addClass("hidden");
|
||||
},
|
||||
|
||||
infScroll: function() {
|
||||
if( this.$el.hasClass('loading') ) return;
|
||||
if (this.$el.hasClass("loading")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var distanceTop = $(window).height() + $(window).scrollTop(),
|
||||
distanceBottom = $(document).height() - distanceTop;
|
||||
if(distanceBottom < 300) this.trigger('renderContacts');
|
||||
if (distanceBottom < 300) {
|
||||
this.trigger("fetchContacts");
|
||||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -10,8 +10,13 @@
|
|||
margin-bottom: 11px;
|
||||
margin-top: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.aspect-controls { margin: 7px -10px 7px 0; }
|
||||
.stream.contacts .aspect-controls {
|
||||
margin-bottom: 7px;
|
||||
margin-left: 30px;
|
||||
margin-right: -10px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +28,7 @@
|
|||
display: none;
|
||||
}
|
||||
#contact_list_search {
|
||||
margin: 11px 30px 0 0;
|
||||
margin: 11px 0 0;
|
||||
width: 150px;
|
||||
&:focus { width: 250px; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@ class ContactsController < ApplicationController
|
|||
# Used by the mobile site
|
||||
format.mobile { set_up_contacts_mobile }
|
||||
|
||||
# Used for mentions in the publisher
|
||||
# Used for mentions in the publisher and pagination on the contacts page
|
||||
format.json {
|
||||
@people = Person.search(params[:q], current_user, only_contacts: true).limit(15)
|
||||
@people = if params[:q].present?
|
||||
Person.search(params[:q], current_user, only_contacts: true).limit(15)
|
||||
else
|
||||
set_up_contacts_json
|
||||
end
|
||||
render json: @people
|
||||
}
|
||||
end
|
||||
|
|
@ -30,30 +34,54 @@ class ContactsController < ApplicationController
|
|||
private
|
||||
|
||||
def set_up_contacts
|
||||
type = params[:set].presence
|
||||
type ||= "by_aspect" if params[:a_id].present?
|
||||
type ||= "receiving"
|
||||
if params[:a_id].present?
|
||||
@aspect = current_user.aspects.find(params[:a_id])
|
||||
gon.preloads[:aspect] = AspectPresenter.new(@aspect).as_json
|
||||
end
|
||||
@contacts_size = current_user.contacts.size
|
||||
end
|
||||
|
||||
@contacts = contacts_by_type(type)
|
||||
@contacts_size = @contacts.length
|
||||
gon.preloads[:contacts] = @contacts.map {|c| ContactPresenter.new(c, current_user).full_hash_with_person }
|
||||
def set_up_contacts_json
|
||||
type = params[:set].presence
|
||||
if params[:a_id].present?
|
||||
type ||= "by_aspect"
|
||||
@aspect = current_user.aspects.find(params[:a_id])
|
||||
end
|
||||
type ||= "receiving"
|
||||
contacts_by_type(type).paginate(page: params[:page], per_page: 25)
|
||||
.map {|c| ContactPresenter.new(c, current_user).full_hash_with_person }
|
||||
end
|
||||
|
||||
def contacts_by_type(type)
|
||||
case type
|
||||
order = ["profiles.first_name ASC", "profiles.last_name ASC", "profiles.diaspora_handle ASC"]
|
||||
contacts = case type
|
||||
when "all"
|
||||
order.unshift "receiving DESC"
|
||||
current_user.contacts
|
||||
when "only_sharing"
|
||||
current_user.contacts.only_sharing
|
||||
when "receiving"
|
||||
current_user.contacts.receiving
|
||||
when "by_aspect"
|
||||
@aspect = current_user.aspects.find(params[:a_id])
|
||||
gon.preloads[:aspect] = AspectPresenter.new(@aspect).as_json
|
||||
current_user.contacts
|
||||
order.unshift "contact_id IS NOT NULL DESC"
|
||||
contacts_by_aspect(@aspect.id)
|
||||
else
|
||||
raise ArgumentError, "unknown type #{type}"
|
||||
end
|
||||
contacts.includes(person: :profile)
|
||||
.order(order)
|
||||
end
|
||||
|
||||
def contacts_by_aspect(aspect_id)
|
||||
contacts = current_user.contacts.arel_table
|
||||
aspect_memberships = AspectMembership.arel_table
|
||||
current_user.contacts.joins(
|
||||
contacts.outer_join(aspect_memberships).on(
|
||||
aspect_memberships[:aspect_id].eq(aspect_id).and(
|
||||
aspect_memberships[:contact_id].eq(contacts[:id])
|
||||
)
|
||||
).join_sources
|
||||
)
|
||||
end
|
||||
|
||||
def set_up_contacts_mobile
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@
|
|||
= link_to @aspect, method: "delete", data: { confirm: t("aspects.edit.confirm_remove_aspect") }, class: "delete contacts_button", id: "delete_aspect" do
|
||||
%i.entypo-trash.contacts-header-icon{title: t("delete")}
|
||||
.pull-right.contact-list-search
|
||||
= search_field_tag :contact_search, "", id: "contact_list_search", class: "search-query form-control", placeholder: t("contacts.index.user_search")
|
||||
%form#contact-search-form{role: "search", method: "get", action: "/search"}
|
||||
= search_field_tag :q, "",
|
||||
id: "contact_list_search",
|
||||
class: "search-query form-control",
|
||||
placeholder: t("contacts.index.user_search")
|
||||
%h3
|
||||
%span#aspect_name
|
||||
= @aspect.name
|
||||
|
|
@ -32,6 +36,13 @@
|
|||
= aspect.submit t('aspects.edit.update'), 'data-disable-with' => t('aspects.edit.updating'), class: "btn btn-default"
|
||||
|
||||
- else
|
||||
.pull-right.contact-list-search
|
||||
%form#contact-search-form{role: "search", method: "get", action: "/search"}
|
||||
= search_field_tag :q, "",
|
||||
id: "contact_list_search",
|
||||
class: "search-query form-control",
|
||||
placeholder: t("contacts.index.user_search")
|
||||
|
||||
%h3
|
||||
- case params["set"]
|
||||
- when "only_sharing"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@
|
|||
.btn.btn-link{ 'data-toggle' => 'modal' }
|
||||
= t('invitations.new.invite_someone_to_join')
|
||||
|
||||
#paginate
|
||||
%span.loader.hidden
|
||||
.spinner
|
||||
|
||||
-if @aspect
|
||||
#new_conversation_pane
|
||||
= render 'shared/modal',
|
||||
|
|
|
|||
|
|
@ -24,51 +24,97 @@ describe ContactsController, :type => :controller do
|
|||
expect(response).to be_success
|
||||
end
|
||||
|
||||
it "assigns contacts" do
|
||||
it "doesn't assign contacts" do
|
||||
get :index
|
||||
contacts = assigns(:contacts)
|
||||
expect(contacts.to_set).to eq(bob.contacts.to_set)
|
||||
end
|
||||
|
||||
it "shows only contacts a user is sharing with" do
|
||||
contact = bob.contacts.first
|
||||
contact.update_attributes(:sharing => false)
|
||||
|
||||
get :index
|
||||
contacts = assigns(:contacts)
|
||||
expect(contacts.to_set).to eq(bob.contacts.receiving.to_set)
|
||||
end
|
||||
|
||||
it "shows all contacts (sharing and receiving)" do
|
||||
contact = bob.contacts.first
|
||||
contact.update_attributes(:sharing => false)
|
||||
|
||||
get :index, :set => "all"
|
||||
contacts = assigns(:contacts)
|
||||
expect(contacts.to_set).to eq(bob.contacts.to_set)
|
||||
expect(contacts).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "format json" do
|
||||
before do
|
||||
@person1 = FactoryGirl.create(:person)
|
||||
bob.share_with(@person1, bob.aspects.first)
|
||||
@person2 = FactoryGirl.create(:person)
|
||||
context "for the contacts search" do
|
||||
before do
|
||||
@person1 = FactoryGirl.create(:person)
|
||||
bob.share_with(@person1, bob.aspects.first)
|
||||
@person2 = FactoryGirl.create(:person)
|
||||
end
|
||||
|
||||
it "succeeds" do
|
||||
get :index, q: @person1.first_name, format: "json"
|
||||
expect(response).to be_success
|
||||
end
|
||||
|
||||
it "responds with json" do
|
||||
get :index, q: @person1.first_name, format: "json"
|
||||
expect(response.body).to eq([@person1].to_json)
|
||||
end
|
||||
|
||||
it "only returns contacts" do
|
||||
get :index, q: @person2.first_name, format: "json"
|
||||
expect(response.body).to eq([].to_json)
|
||||
end
|
||||
end
|
||||
|
||||
it "succeeds" do
|
||||
get :index, q: @person1.first_name, format: "json"
|
||||
expect(response).to be_success
|
||||
end
|
||||
context "for pagination on the contacts page" do
|
||||
context "without parameters" do
|
||||
it "returns contacts" do
|
||||
get :index, format: "json", page: "1"
|
||||
contact_ids = JSON.parse(response.body).map {|c| c["id"] }
|
||||
expect(contact_ids.to_set).to eq(bob.contacts.map(&:id).to_set)
|
||||
end
|
||||
|
||||
it "responds with json" do
|
||||
get :index, q: @person1.first_name, format: "json"
|
||||
expect(response.body).to eq([@person1].to_json)
|
||||
end
|
||||
it "returns only contacts which are receiving (the user is sharing with them)" do
|
||||
contact = bob.contacts.first
|
||||
contact.update_attributes(receiving: false)
|
||||
|
||||
it "only returns contacts" do
|
||||
get :index, q: @person2.first_name, format: "json"
|
||||
expect(response.body).to eq([].to_json)
|
||||
get :index, format: "json", page: "1"
|
||||
contact_ids = JSON.parse(response.body).map {|c| c["id"] }
|
||||
expect(contact_ids.to_set).to eq(bob.contacts.receiving.map(&:id).to_set)
|
||||
expect(contact_ids).not_to include(contact.id)
|
||||
end
|
||||
end
|
||||
|
||||
context "set: all" do
|
||||
before do
|
||||
contact = bob.contacts.first
|
||||
contact.update_attributes(receiving: false)
|
||||
end
|
||||
|
||||
it "returns all contacts (sharing and receiving)" do
|
||||
get :index, format: "json", page: "1", set: "all"
|
||||
contact_ids = JSON.parse(response.body).map {|c| c["id"] }
|
||||
expect(contact_ids.to_set).to eq(bob.contacts.map(&:id).to_set)
|
||||
end
|
||||
|
||||
it "sorts contacts by receiving status" do
|
||||
get :index, format: "json", page: "1", set: "all"
|
||||
contact_ids = JSON.parse(response.body).map {|c| c["id"] }
|
||||
expect(contact_ids).to eq(bob.contacts.order("receiving DESC").map(&:id))
|
||||
expect(contact_ids.last).to eq(bob.contacts.first.id)
|
||||
end
|
||||
end
|
||||
|
||||
context "with an aspect id" do
|
||||
before do
|
||||
@aspect = bob.aspects.create(name: "awesome contacts")
|
||||
@person = FactoryGirl.create(:person)
|
||||
bob.share_with(@person, @aspect)
|
||||
end
|
||||
|
||||
it "returns all contacts" do
|
||||
get :index, format: "json", a_id: @aspect.id, page: "1"
|
||||
contact_ids = JSON.parse(response.body).map {|c| c["id"] }
|
||||
expect(contact_ids.to_set).to eq(bob.contacts.map(&:id).to_set)
|
||||
end
|
||||
|
||||
it "sorts contacts by aspect memberships" do
|
||||
get :index, format: "json", a_id: @aspect.id, page: "1"
|
||||
expect(JSON.parse(response.body).first["person"]["id"]).to eq(@person.id)
|
||||
|
||||
get :index, format: "json", a_id: bob.aspects.first.id, page: "1"
|
||||
expect(JSON.parse(response.body).first["person"]["id"]).not_to eq(@person.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ describe ContactsController, :type => :controller do
|
|||
it "generates the aspects_manage fixture", :fixture => true do
|
||||
get :index, :a_id => @aspect.id
|
||||
save_fixture(html_for("body"), "aspects_manage")
|
||||
save_fixture(controller.gon.preloads[:contacts].to_json, "aspects_manage_contacts_json")
|
||||
end
|
||||
|
||||
it "generates the aspects_manage_contacts_json fixture", fixture: true do
|
||||
get :index, format: :json, a_id: @aspect.id, page: "1"
|
||||
save_fixture(response.body, "aspects_manage_contacts_json")
|
||||
end
|
||||
|
||||
it "generates the contacts_json fixture", :fixture => true do
|
||||
|
|
|
|||
|
|
@ -88,19 +88,6 @@ describe("app.pages.Contacts", function(){
|
|||
});
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateBadgeCount", function() {
|
||||
it("increases the badge count of an aspect", function() {
|
||||
var aspect = $("#aspect_nav .aspect").eq(0);
|
||||
|
|
|
|||
|
|
@ -2,76 +2,199 @@ 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.contacts = new app.collections.Contacts();
|
||||
this.contactsData = $.parseJSON(spec.readFixture("contacts_json"));
|
||||
app.aspect = new app.models.Aspect(this.contactsData[0].aspect_memberships[0].aspect);
|
||||
this.view = new app.views.ContactStream({
|
||||
collection : this.contacts,
|
||||
el: $('.stream.contacts #contact_stream')
|
||||
el: $(".stream.contacts #contact_stream"),
|
||||
urlParams: "set=all"
|
||||
});
|
||||
|
||||
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});
|
||||
new app.views.ContactStream({collection: this.contacts});
|
||||
expect($.fn.scroll).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("binds 'fetchContacts'", function() {
|
||||
spyOn(app.views.ContactStream.prototype, "fetchContacts");
|
||||
this.view = new app.views.ContactStream({collection: this.contacts});
|
||||
this.view.trigger("fetchContacts");
|
||||
expect(app.views.ContactStream.prototype.fetchContacts).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sets the current page for pagination to 1", function() {
|
||||
expect(this.view.page).toBe(1);
|
||||
});
|
||||
|
||||
it("sets urlParams to the given value", function() {
|
||||
expect(this.view.urlParams).toBe("set=all");
|
||||
});
|
||||
});
|
||||
|
||||
describe("search", function() {
|
||||
it("filters the contacts", function() {
|
||||
describe("render", function() {
|
||||
it("calls fetchContacts", function() {
|
||||
spyOn(this.view, "fetchContacts");
|
||||
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");
|
||||
expect(this.view.fetchContacts).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("fetchContacts", function() {
|
||||
it("adds the loading class", function() {
|
||||
expect(this.view.$el).not.toHaveClass("loading");
|
||||
this.view.fetchContacts();
|
||||
expect(this.view.$el).toHaveClass("loading");
|
||||
});
|
||||
|
||||
it("displays the loading spinner", function() {
|
||||
expect($("#paginate .loader")).toHaveClass("hidden");
|
||||
this.view.fetchContacts();
|
||||
expect($("#paginate .loader")).not.toHaveClass("hidden");
|
||||
});
|
||||
|
||||
it("calls $.ajax with the URL given by _fetchUrl", function() {
|
||||
spyOn(this.view, "_fetchUrl").and.returnValue("/myAwesomeFetchUrl?foo=bar");
|
||||
this.view.fetchContacts();
|
||||
expect(jasmine.Ajax.requests.mostRecent().url).toBe("/myAwesomeFetchUrl?foo=bar");
|
||||
});
|
||||
|
||||
it("calls onEmptyResponse on an empty response", function() {
|
||||
spyOn(this.view, "onEmptyResponse");
|
||||
this.view.fetchContacts();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: JSON.stringify([])});
|
||||
expect(this.view.onEmptyResponse).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls appendContactViews on a non-empty response", function() {
|
||||
spyOn(this.view, "appendContactViews");
|
||||
this.view.fetchContacts();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: JSON.stringify(this.contactsData)});
|
||||
expect(this.view.appendContactViews).toHaveBeenCalledWith(this.contactsData);
|
||||
});
|
||||
|
||||
it("increases the current page on a non-empty response", function() {
|
||||
this.view.page = 42;
|
||||
this.view.fetchContacts();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: JSON.stringify(this.contactsData)});
|
||||
expect(this.view.page).toBe(43);
|
||||
});
|
||||
});
|
||||
|
||||
describe("_fetchUrl", function() {
|
||||
it("returns the correct URL to fetch contacts", function() {
|
||||
this.view.page = 15;
|
||||
this.view.urlParams = undefined;
|
||||
expect(this.view._fetchUrl()).toBe("/contacts.json?page=15");
|
||||
});
|
||||
|
||||
it("appends urlParams if those are set", function() {
|
||||
this.view.page = 23;
|
||||
expect(this.view._fetchUrl()).toBe("/contacts.json?page=23&set=all");
|
||||
});
|
||||
});
|
||||
|
||||
describe("onEmptyResponse", function() {
|
||||
context("with an empty collection", function() {
|
||||
it("adds a 'no contacts' div", function() {
|
||||
this.view.onEmptyResponse();
|
||||
expect(this.view.$("#no_contacts").text().trim()).toBe(Diaspora.I18n.t("contacts.search_no_results"));
|
||||
});
|
||||
|
||||
it("hides the loading spinner", function() {
|
||||
this.view.$el.addClass("loading");
|
||||
$("#paginate .loader").removeClass("hidden");
|
||||
this.view.onEmptyResponse();
|
||||
expect(this.view.$el).not.toHaveClass("loading");
|
||||
expect($("#paginate .loader")).toHaveClass("hidden");
|
||||
});
|
||||
|
||||
it("unbinds 'fetchContacts'", function() {
|
||||
spyOn(this.view, "off");
|
||||
this.view.onEmptyResponse();
|
||||
expect(this.view.off).toHaveBeenCalledWith("fetchContacts");
|
||||
});
|
||||
});
|
||||
|
||||
context("with a non-empty collection", function() {
|
||||
beforeEach(function() {
|
||||
this.view.collection.add(factory.contact());
|
||||
});
|
||||
|
||||
it("adds no 'no contacts' div", function() {
|
||||
this.view.onEmptyResponse();
|
||||
expect(this.view.$("#no_contacts").length).toBe(0);
|
||||
});
|
||||
|
||||
it("hides the loading spinner", function() {
|
||||
this.view.$el.addClass("loading");
|
||||
$("#paginate .loader").removeClass("hidden");
|
||||
this.view.onEmptyResponse();
|
||||
expect(this.view.$el).not.toHaveClass("loading");
|
||||
expect($("#paginate .loader")).toHaveClass("hidden");
|
||||
});
|
||||
|
||||
it("unbinds 'fetchContacts'", function() {
|
||||
spyOn(this.view, "off");
|
||||
this.view.onEmptyResponse();
|
||||
expect(this.view.off).toHaveBeenCalledWith("fetchContacts");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("appendContactViews", function() {
|
||||
it("hides the loading spinner", function() {
|
||||
this.view.$el.addClass("loading");
|
||||
$("#paginate .loader").removeClass("hidden");
|
||||
this.view.appendContactViews(this.contactsData);
|
||||
expect(this.view.$el).not.toHaveClass("loading");
|
||||
expect($("#paginate .loader")).toHaveClass("hidden");
|
||||
});
|
||||
|
||||
it("adds all contacts to an empty collection", function() {
|
||||
expect(this.view.collection.length).toBe(0);
|
||||
this.view.appendContactViews(this.contactsData);
|
||||
expect(this.view.collection.length).toBe(this.contactsData.length);
|
||||
expect(this.view.collection.pluck("id")).toEqual(_.pluck(this.contactsData, "id"));
|
||||
});
|
||||
|
||||
it("appends contacts to an existing collection", function() {
|
||||
this.view.collection.add(this.contactsData[0]);
|
||||
expect(this.view.collection.length).toBe(1);
|
||||
this.view.appendContactViews(_.rest(this.contactsData));
|
||||
expect(this.view.collection.length).toBe(this.contactsData.length);
|
||||
expect(this.view.collection.pluck("id")).toEqual(_.pluck(this.contactsData, "id"));
|
||||
});
|
||||
|
||||
it("renders all added contacts", function() {
|
||||
expect(this.view.$(".stream_element.contact").length).toBe(0);
|
||||
this.view.appendContactViews(this.contactsData);
|
||||
expect(this.view.$(".stream_element.contact").length).toBe(this.contactsData.length);
|
||||
});
|
||||
|
||||
it("appends contacts to an existing contact list", function() {
|
||||
this.view.appendContactViews([this.contactsData[0]]);
|
||||
expect(this.view.$(".stream_element.contact").length).toBe(1);
|
||||
this.view.appendContactViews(_.rest(this.contactsData));
|
||||
expect(this.view.$(".stream_element.contact").length).toBe(this.contactsData.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe("infScroll", function() {
|
||||
beforeEach(function() {
|
||||
this.view.off("renderContacts");
|
||||
this.view.off("fetchContacts");
|
||||
this.fn = jasmine.createSpy();
|
||||
this.view.on("renderContacts", this.fn);
|
||||
this.view.on("fetchContacts", 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() {
|
||||
it("triggers fetchContacts 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue