From cfa55896a51a88f9f9c0d65905a9e41a4206757b Mon Sep 17 00:00:00 2001 From: JC Brand Date: Fri, 25 Jul 2014 09:58:42 +0200 Subject: [PATCH] Trying to use a document fragment for the roster view --- converse.js | 54 ++++++++++++++++++++++++++++------------------ spec/controlbox.js | 32 ++++++++++++++++----------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/converse.js b/converse.js index e2f9d1ffe..8434331b8 100644 --- a/converse.js +++ b/converse.js @@ -3266,7 +3266,8 @@ toggle_state: toggle_state }); } - this.$el.hide().html(roster_markup); + this.$fragment = $(''); + this.$fragment.append($(roster_markup)); }, onAdd: function (item) { @@ -3281,6 +3282,14 @@ } }, + showRoster: function () { + if (this.$fragment) { + this.$el.html(this.$fragment) + delete this.$fragment; + } + return this; + }, + onChange: function (item) { if ((_.size(item.changed) === 1) && _.contains(_.keys(item.changed), 'sorted')) { return; @@ -3342,6 +3351,17 @@ return this; }, + getRosterElement: function () { + // TODO: see is _ensureElement can be used. + // Return the document fragment if it exists. + var $el; + if (this.$fragment) { + return this.$fragment; + } else { + return this.$el; + } + }, + addRosterItem: function (item) { if ((converse.show_only_online_users) && (item.get('chat_status') !== 'online')) { return this; @@ -3352,13 +3372,14 @@ return this; } view.render() + var $el = this.getRosterElement(); if (view.$el.hasClass('current-xmpp-contact')) { // TODO: need to add group support - this.$('.roster-group').after(view.el); + $el.find('.roster-group').after(view.el); } else if (view.$el.hasClass('pending-xmpp-contact')) { - this.$('#pending-xmpp-contacts').after(view.el); + $el.find('#pending-xmpp-contacts').after(view.el); } else if (view.$el.hasClass('requesting-xmpp-contact')) { - this.$('#xmpp-contact-requests').after(view.render().el); + $el.find('#xmpp-contact-requests').after(view.render().el); } return this; }, @@ -3379,9 +3400,10 @@ }, toggleHeaders: function () { - var $contact_requests = this.$('#xmpp-contact-requests'), - $pending_contacts = this.$('#pending-xmpp-contacts'); - var $groups = this.$el.find('.roster-group'); + var $el = this.getRosterElement(); + var $contact_requests = $el.find('#xmpp-contact-requests'), + $pending_contacts = $el.find('#pending-xmpp-contacts'); + var $groups = $el.find('.roster-group'); // Hide the headers if there are no contacts under them _.each([$groups, $contact_requests, $pending_contacts], function (h) { var show_or_hide = function (h) { @@ -3431,29 +3453,19 @@ * 1). See if the jquery detach method can be somehow used to avoid DOM reflows. * 2). Likewise see if documentFragment can be used. */ - this.$el.find('.roster-group').each($.proxy(function (idx, group) { + var $el = this.getRosterElement(); + $el.find('.roster-group').each($.proxy(function (idx, group) { var $group = $(group); var $contacts = $group.nextUntil('dt', 'dd.current-xmpp-contact'); $group.after($contacts.tsort({sortFunction: this.sortFunction, data: 'status'}, 'a')); },this)); // Also sort pending and requesting contacts var crit = {order:'asc'}, - $contact_requests = this.$('#xmpp-contact-requests'), - $pending_contacts = this.$('#pending-xmpp-contacts'); + $contact_requests = $el.find('#xmpp-contact-requests'), + $pending_contacts = $el.find('#pending-xmpp-contacts'); $pending_contacts.after($pending_contacts.siblings('dd.pending-xmpp-contact').tsort(crit)); $contact_requests.after($contact_requests.siblings('dd.requesting-xmpp-contact').tsort(crit)); return this; - }, - - showRoster: function () { - if (!this.$el.is(':visible')) { - // Once all initial roster items have been added, we - // can show the roster. - // TODO: It would be more efficient to use a - // documentFragment and then put that in the DOM - this.$el.show(); - } - return this; } }); diff --git a/spec/controlbox.js b/spec/controlbox.js index c2aef4176..c8f1859de 100644 --- a/spec/controlbox.js +++ b/spec/controlbox.js @@ -129,28 +129,32 @@ describe("The Contacts Roster", $.proxy(function (mock, utils) { describe("Pending Contacts", $.proxy(function () { - beforeEach($.proxy(function () { - runs(function () { - converse.rosterview.model.reset(); - utils.createContacts('pending').openControlBox(); - }); - waits(50); - runs(function () { - utils.openContactsPanel(); - }); - }, converse)); + function _clearContacts () { + utils.clearBrowserStorage(); + converse.rosterview.model.reset(); + converse.rosterview.initialize(); + }; + + function _addContacts () { + _clearContacts(); + // Must be initialized, so that render is called and documentFragment set up. + utils.createContacts('pending').openControlBox(); + utils.openContactsPanel(); + }; it("do not have a header if there aren't any", $.proxy(function () { - converse.rosterview.model.reset(); + _addContacts(); + this.rosterview.model.reset(); expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('none'); }, converse)); it("can be collapsed under their own header", $.proxy(function () { + _addContacts(); checkHeaderToggling.apply(this, [this.rosterview.$el.find('dt#pending-xmpp-contacts')]); }, converse)); it("can be added to the roster", $.proxy(function () { - converse.rosterview.model.reset(); // We want to manually create users so that we can spy + _clearContacts(); spyOn(converse, 'emit'); spyOn(this.rosterview, 'updateRoster').andCallThrough(); runs($.proxy(function () { @@ -171,6 +175,7 @@ }, converse)); it("can be removed by the user", $.proxy(function () { + _addContacts(); var jid = mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; var view = this.rosterview.get(jid); spyOn(window, 'confirm').andReturn(true); @@ -190,6 +195,7 @@ }, converse)); it("will lose their own header once the last one has been removed", $.proxy(function () { + _addContacts(); var view; spyOn(window, 'confirm').andReturn(true); for (i=0; i