diff --git a/src/converse-controlbox.js b/src/converse-controlbox.js index df4397dde..61a90a75c 100644 --- a/src/converse-controlbox.js +++ b/src/converse-controlbox.js @@ -262,7 +262,10 @@ */ converse.rosterview = new converse.RosterView({model: converse.rostergroups}); this.contactspanel.$el.append(converse.rosterview.$el); - converse.rosterview.render().fetch().update(); + converse.rosterview.render().populate().then(function () { + converse.rosterview.update(); + converse.sendInitialPresence(); + }); return this; }, diff --git a/src/converse-core.js b/src/converse-core.js index 78fa41cb3..0d6a532f8 100755 --- a/src/converse-core.js +++ b/src/converse-core.js @@ -677,6 +677,13 @@ }, null, 'presence', null); }; + + this.sendInitialPresence = function () { + if (converse.send_initial_presence) { + converse.xmppstatus.sendPresence(); + } + }; + this.onStatusInitialized = function () { this.registerIntervalHandler(); this.initRoster(); @@ -865,6 +872,36 @@ } }, + fetchRosterContacts: function () { + /* Fetches the roster contacts, first by trying the + * sessionStorage cache, and if that's empty, then by querying + * the XMPP server. + * + * Returns a promise which resolves once the contacts have been + * fetched. + */ + var deferred = new $.Deferred(); + this.fetch({ + add: true, + success: function (collection) { + if (collection.length === 0) { + /* We don't have any roster contacts stored in sessionStorage, + * so lets fetch the roster from the XMPP server. We pass in + * 'sendPresence' as callback method, because after initially + * fetching the roster we are ready to receive presence + * updates from our contacts. + */ + converse.send_initial_presence = true; + converse.roster.fetchFromServer(deferred.resolve); + } else { + converse.emit('cachedRoster', collection); + deferred.resolve(); + } + } + }); + return deferred.promise(); + }, + subscribeToSuggestedItems: function (msg) { $(msg).find('item').each(function (i, items) { if (this.getAttribute('action') === 'add') { @@ -1204,6 +1241,22 @@ this.RosterGroups = Backbone.Collection.extend({ model: converse.RosterGroup, + + fetchRosterGroups: function () { + /* Fetches all the roster groups from sessionStorage. + * + * Returns a promise which resolves once the groups have been + * returned. + */ + var deferred = new $.Deferred(); + this.fetch({ + silent: true, // We need to first have all groups before + // we can start positioning them, so we set + // 'silent' to true. + success: deferred.resolve + }); + return deferred.promise(); + } }); diff --git a/src/converse-rosterview.js b/src/converse-rosterview.js index 442629725..da1ae49b8 100644 --- a/src/converse-rosterview.js +++ b/src/converse-rosterview.js @@ -296,43 +296,16 @@ return this; }, - fetch: function () { - this.model.fetch({ - silent: true, // We use the success handler to handle groups that were added, - // we need to first have all groups before positionFetchedGroups - // will work properly. - success: function (collection, resp, options) { - if (collection.length !== 0) { - this.positionFetchedGroups(collection, resp, options); - } - converse.roster.fetch({ - add: true, - success: function (collection) { - if (collection.length === 0) { - /* We don't have any roster contacts stored in sessionStorage, - * so lets fetch the roster from the XMPP server. We pass in - * 'sendPresence' as callback method, because after initially - * fetching the roster we are ready to receive presence - * updates from our contacts. - */ - converse.roster.fetchFromServer( - converse.xmppstatus.sendPresence.bind(converse.xmppstatus)); - } else { - converse.emit('cachedRoster', collection); - if (converse.send_initial_presence) { - /* We're not going to fetch the roster again because we have - * it already cached in sessionStorage, but we still need to - * send out a presence stanza because this is a new session. - * See: https://github.com/jcbrand/converse.js/issues/536 - */ - converse.xmppstatus.sendPresence(); - } - } - } - }); - }.bind(this) - }); - return this; + populate: function () { + /* Fetch the roster groups, position them and then fetch + * the roster contacts. + */ + var deferred = new $.Deferred(); + this.model.fetchRosterGroups().then(function () { + this.positionFetchedGroups.apply(this, arguments); + converse.roster.fetchRosterContacts().then(deferred.resolve); + }.bind(this)); + return deferred.promise(); }, filter: function (query, type) { @@ -448,6 +421,9 @@ * positioned aren't already in inserted into the * roster DOM element. */ + if (model.length === 0) { + return; + } model.sort(); model.each(function (group, idx) { var view = this.get(group.get('name'));