Roster fixes related to reconnecting

Avoid `An 'url' property must be specified` error by properly clearing
presence data upon teardown and then resetting the browserStorage upon
reconnection.

Store contact resources in a Backbone collection
This commit is contained in:
JC Brand 2019-01-28 11:24:46 +01:00
parent 4e9e532a06
commit 3cbc99a3f2
4 changed files with 194 additions and 195 deletions

132
dist/converse.js vendored
View File

@ -49505,13 +49505,12 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
}
const contact_jid = this.model.get('jid');
const resources = this.model.presence.get('resources');
if (_.isEmpty(resources)) {
if (this.model.presence.resources.length === 0) {
return;
}
const results = await Promise.all(_.map(_.keys(resources), resource => _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${resource}`)));
const results = await Promise.all(this.model.presence.resources.map(res => _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${res.get('name')}`)));
if (_.filter(results, 'length').length) {
const html = templates_spoiler_button_html__WEBPACK_IMPORTED_MODULE_16___default()(this.model.toJSON());
@ -67777,7 +67776,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
_converse.registerPresenceHandler = function () {
_converse.unregisterPresenceHandler();
_converse.presence_ref = _converse.connection.addHandler(function (presence) {
_converse.presence_ref = _converse.connection.addHandler(presence => {
_converse.roster.presenceHandler(presence);
return true;
@ -67843,12 +67842,35 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
}
};
const Resource = Backbone.Model.extend({
'idAttribute': 'name'
});
const Resources = Backbone.Collection.extend({
'model': Resource
});
_converse.Presence = Backbone.Model.extend({
defaults() {
return {
'show': 'offline',
'resources': {}
};
defaults: {
'show': 'offline'
},
initialize() {
this.resources = new Resources();
const id = `converse.identities-${this.get('jid')}`;
this.resources.browserStorage = new Backbone.BrowserStorage.session(id);
this.resources.on('update', this.onResourcesChanged, this);
this.resources.on('change', this.onResourcesChanged, this);
},
onResourcesChanged() {
const hpr = this.getHighestPriorityResource();
const show = _.get(hpr, 'attributes.show', 'offline');
if (this.get('show') !== show) {
this.save({
'show': show
});
}
},
getHighestPriorityResource() {
@ -67857,15 +67879,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
* If multiple resources have the same priority, take the
* latest one.
*/
const resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) {
const val = _.flow(_.values, _.partial(_.sortBy, _, ['priority', 'timestamp']), _.reverse)(resources)[0];
if (!_.isUndefined(val)) {
return val;
}
}
return this.resources.sortBy(r => `${r.get('priority')}-${r.get('timestamp')}`).reverse()[0];
},
addResource(presence) {
@ -67875,52 +67889,35 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
* Also updates the presence if the resource has higher priority (and is newer).
*/
const jid = presence.getAttribute('from'),
show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
resource = Strophe.getResourceFromJid(jid),
name = Strophe.getResourceFromJid(jid),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
timestamp = _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
let priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
'name': resource,
'priority': priority,
'show': show,
'timestamp': timestamp
priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0,
resource = this.resources.get(name),
settings = {
'name': name,
'priority': _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
'show': _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
'timestamp': _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format()
};
const changed = {
'resources': resources
};
const hpr = this.getHighestPriorityResource();
if (priority == hpr.priority && timestamp == hpr.timestamp) {
// Only set the "global" presence if this is the newest resource
// with the highest priority
changed.show = show;
if (resource) {
resource.save(settings);
} else {
this.resources.create(settings);
}
this.save(changed);
return resources;
},
removeResource(resource) {
removeResource(name) {
/* Remove the passed in resource from the resources map.
*
* Also redetermines the presence given that there's one less
* resource.
*/
let resources = this.get('resources');
const resource = this.resources.get(name);
if (!_.isObject(resources)) {
resources = {};
} else {
delete resources[resource];
if (resource) {
resource.destroy();
}
this.save({
'resources': resources,
'show': _.propertyOf(this.getHighestPriorityResource())('show') || 'offline'
});
}
});
@ -68326,7 +68323,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
if (from && from !== _converse.bare_jid) {
// https://tools.ietf.org/html/rfc6121#page-15
//
//
// A receiving client MUST ignore the stanza unless it has no 'from'
// attribute (i.e., implicitly from the bare JID of the user's
// account) or it has a 'from' attribute whose value matches the
@ -68686,8 +68683,16 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
_converse.api.listen.on('afterTearDown', () => {
if (_converse.presences) {
_converse.presences.off().reset(); // Remove presences
_converse.presences.each(p => {
p.resources.each(r => r.destroy({
'silent': true
}));
p.save({
'show': 'offline'
}, {
'silent': true
});
});
}
});
@ -68700,11 +68705,12 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
_converse.api.listen.on('statusInitialized', reconnecting => {
if (!reconnecting) {
_converse.presences = new _converse.Presences();
_converse.presences.browserStorage = new Backbone.BrowserStorage.session(b64_sha1(`converse.presences-${_converse.bare_jid}`));
_converse.presences.fetch();
}
_converse.presences.browserStorage = new Backbone.BrowserStorage.session(b64_sha1(`converse.presences-${_converse.bare_jid}`));
_converse.presences.fetch();
_converse.emit('presencesInitialized', reconnecting);
});
@ -68723,9 +68729,9 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
_converse.roster.onConnected();
_converse.populateRoster(reconnecting);
_converse.registerPresenceHandler();
_converse.populateRoster(reconnecting);
});
/************************ API ************************/
// API methods only available to plugins
@ -68739,7 +68745,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
'contacts': {
/**
* This method is used to retrieve roster contacts.
*
*
* @method _converse.api.contacts.get
* @params {(string[]|string)} jid|jids The JID or JIDs of
* the contacts to be returned.
@ -68752,7 +68758,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
* const contact = _converse.api.contacts.get('buddy@example.com')
* // ...
* });
*
*
* @example
* // To get multiple contacts, pass in an array of JIDs:
* _converse.api.listen.on('rosterContactsFetched', function () {
@ -68761,7 +68767,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
* )
* // ...
* });
*
*
* @example
* // To return all contacts, simply call ``get`` without any parameters:
* _converse.api.listen.on('rosterContactsFetched', function () {
@ -68785,7 +68791,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
/**
* Add a contact.
*
*
* @method _converse.api.contacts.add
* @param {string} jid The JID of the contact to be added
* @param {string} [name] A custom name to show the user by

View File

@ -125,9 +125,9 @@
test_utils.openControlBox();
test_utils.createContacts(_converse, 'current'); // Create some contacts so that we can test positioning
var contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@localhost';
var contact = _converse.roster.get(contact_jid);
var stanza = $(
const contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@localhost';
const contact = _converse.roster.get(contact_jid);
let stanza = $(
'<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+
' from="'+contact_jid+'/priority-1-resource">'+
@ -141,9 +141,9 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(contact.presence.get('show')).toBe('online');
expect(_.keys(contact.presence.get('resources')).length).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.resources.length).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -157,12 +157,13 @@
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="'+contact_jid+'/priority-0-resource"/>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
expect(_.keys(contact.presence.get('resources')).length).toBe(2);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.get('show')).toBe('online');
expect(contact.presence.resources.length).toBe(2);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -172,14 +173,14 @@
' <show>dnd</show>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
expect(_.keys(contact.presence.get('resources')).length).toBe(3);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
expect(contact.presence.get('show')).toBe('dnd');
expect(contact.presence.resources.length).toBe(3);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -190,15 +191,15 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
expect(_.keys(contact.presence.get('resources')).length).toBe(4);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
expect(contact.presence.get('resources')['priority-3-resource']['priority']).toBe(3);
expect(contact.presence.get('resources')['priority-3-resource']['show']).toBe('away');
expect(contact.presence.resources.length).toBe(4);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -210,17 +211,17 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
expect(_.keys(contact.presence.get('resources')).length).toBe(5);
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
expect(contact.presence.get('resources')['priority-3-resource']['priority']).toBe(3);
expect(contact.presence.get('resources')['priority-3-resource']['show']).toBe('away');
expect(contact.presence.resources.length).toBe(5);
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -230,15 +231,15 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
expect(_.keys(contact.presence.get('resources')).length).toBe(4);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
expect(contact.presence.resources.length).toBe(4);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -248,13 +249,13 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
expect(_.keys(contact.presence.get('resources')).length).toBe(3);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
expect(contact.presence.resources.length).toBe(3);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -264,11 +265,11 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
expect(_.keys(contact.presence.get('resources')).length).toBe(2);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
expect(contact.presence.resources.length).toBe(2);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -278,9 +279,9 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('xa');
expect(_.keys(contact.presence.get('resources')).length).toBe(1);
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
expect(contact.presence.resources.length).toBe(1);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
stanza = $(
'<presence xmlns="jabber:client"'+
@ -290,7 +291,7 @@
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('offline');
expect(_.keys(contact.presence.get('resources')).length).toBe(0);
expect(contact.presence.resources.length).toBe(0);
done();
}));
});

View File

@ -431,13 +431,14 @@ converse.plugins.add('converse-chatview', {
return;
}
const contact_jid = this.model.get('jid');
const resources = this.model.presence.get('resources');
if (_.isEmpty(resources)) {
if (this.model.presence.resources.length === 0) {
return;
}
const results = await Promise.all(_.map(_.keys(resources),
resource => _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${resource}`)
));
const results = await Promise.all(
this.model.presence.resources.map(
res => _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${res.get('name')}`)
)
);
if (_.filter(results, 'length').length) {
const html = tpl_spoiler_button(this.model.toJSON());
if (_converse.visible_toolbar_buttons.emoji) {

View File

@ -38,8 +38,7 @@ converse.plugins.add('converse-roster', {
_converse.registerPresenceHandler = function () {
_converse.unregisterPresenceHandler();
_converse.presence_ref = _converse.connection.addHandler(
function (presence) {
_converse.presence_ref = _converse.connection.addHandler(presence => {
_converse.roster.presenceHandler(presence);
return true;
}, null, 'presence', null);
@ -102,12 +101,28 @@ converse.plugins.add('converse-roster', {
}
};
const Resource = Backbone.Model.extend({'idAttribute': 'name'});
const Resources = Backbone.Collection.extend({'model': Resource});
_converse.Presence = Backbone.Model.extend({
defaults () {
return {
'show': 'offline',
'resources': {}
defaults: {
'show': 'offline'
},
initialize () {
this.resources = new Resources();
const id = `converse.identities-${this.get('jid')}`;
this.resources.browserStorage = new Backbone.BrowserStorage.session(id);
this.resources.on('update', this.onResourcesChanged, this);
this.resources.on('change', this.onResourcesChanged, this);
},
onResourcesChanged () {
const hpr = this.getHighestPriorityResource();
const show = _.get(hpr, 'attributes.show', 'offline');
if (this.get('show') !== show) {
this.save({'show': show});
}
},
@ -117,17 +132,7 @@ converse.plugins.add('converse-roster', {
* If multiple resources have the same priority, take the
* latest one.
*/
const resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) {
const val = _.flow(
_.values,
_.partial(_.sortBy, _, ['priority', 'timestamp']),
_.reverse
)(resources)[0];
if (!_.isUndefined(val)) {
return val;
}
}
return this.resources.sortBy(r => `${r.get('priority')}-${r.get('timestamp')}`).reverse()[0];
},
addResource (presence) {
@ -137,52 +142,35 @@ converse.plugins.add('converse-roster', {
* Also updates the presence if the resource has higher priority (and is newer).
*/
const jid = presence.getAttribute('from'),
show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
resource = Strophe.getResourceFromJid(jid),
name = Strophe.getResourceFromJid(jid),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
timestamp = _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
let priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
'name': resource,
'priority': priority,
'show': show,
'timestamp': timestamp
};
const changed = {'resources': resources};
const hpr = this.getHighestPriorityResource();
if (priority == hpr.priority && timestamp == hpr.timestamp) {
// Only set the "global" presence if this is the newest resource
// with the highest priority
changed.show = show;
priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0,
resource = this.resources.get(name),
settings = {
'name': name,
'priority': _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
'show': _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
'timestamp': _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format()
};
if (resource) {
resource.save(settings);
} else {
this.resources.create(settings);
}
this.save(changed);
return resources;
},
removeResource (resource) {
removeResource (name) {
/* Remove the passed in resource from the resources map.
*
* Also redetermines the presence given that there's one less
* resource.
*/
let resources = this.get('resources');
if (!_.isObject(resources)) {
resources = {};
} else {
delete resources[resource];
const resource = this.resources.get(name);
if (resource) {
resource.destroy();
}
this.save({
'resources': resources,
'show': _.propertyOf(
this.getHighestPriorityResource())('show') || 'offline'
});
},
}
});
@ -539,7 +527,7 @@ converse.plugins.add('converse-roster', {
const from = iq.getAttribute('from');
if (from && from !== _converse.bare_jid) {
// https://tools.ietf.org/html/rfc6121#page-15
//
//
// A receiving client MUST ignore the stanza unless it has no 'from'
// attribute (i.e., implicitly from the bare JID of the user's
// account) or it has a 'from' attribute whose value matches the
@ -847,7 +835,10 @@ converse.plugins.add('converse-roster', {
_converse.api.listen.on('afterTearDown', () => {
if (_converse.presences) {
_converse.presences.off().reset(); // Remove presences
_converse.presences.each(p => {
p.resources.each(r => r.destroy({'silent': true}));
p.save({'show': 'offline'}, {'silent': true})
});
}
});
@ -860,10 +851,10 @@ converse.plugins.add('converse-roster', {
_converse.api.listen.on('statusInitialized', (reconnecting) => {
if (!reconnecting) {
_converse.presences = new _converse.Presences();
_converse.presences.browserStorage =
new Backbone.BrowserStorage.session(b64_sha1(`converse.presences-${_converse.bare_jid}`));
_converse.presences.fetch();
}
_converse.presences.browserStorage =
new Backbone.BrowserStorage.session(b64_sha1(`converse.presences-${_converse.bare_jid}`));
_converse.presences.fetch();
_converse.emit('presencesInitialized', reconnecting);
});
@ -879,8 +870,8 @@ converse.plugins.add('converse-roster', {
_converse.initRoster();
}
_converse.roster.onConnected();
_converse.populateRoster(reconnecting);
_converse.registerPresenceHandler();
_converse.populateRoster(reconnecting);
});
@ -895,7 +886,7 @@ converse.plugins.add('converse-roster', {
'contacts': {
/**
* This method is used to retrieve roster contacts.
*
*
* @method _converse.api.contacts.get
* @params {(string[]|string)} jid|jids The JID or JIDs of
* the contacts to be returned.
@ -908,7 +899,7 @@ converse.plugins.add('converse-roster', {
* const contact = _converse.api.contacts.get('buddy@example.com')
* // ...
* });
*
*
* @example
* // To get multiple contacts, pass in an array of JIDs:
* _converse.api.listen.on('rosterContactsFetched', function () {
@ -917,7 +908,7 @@ converse.plugins.add('converse-roster', {
* )
* // ...
* });
*
*
* @example
* // To return all contacts, simply call ``get`` without any parameters:
* _converse.api.listen.on('rosterContactsFetched', function () {
@ -938,7 +929,7 @@ converse.plugins.add('converse-roster', {
},
/**
* Add a contact.
*
*
* @method _converse.api.contacts.add
* @param {string} jid The JID of the contact to be added
* @param {string} [name] A custom name to show the user by