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:
parent
4e9e532a06
commit
3cbc99a3f2
122
dist/converse.js
vendored
122
dist/converse.js
vendored
@ -49505,13 +49505,12 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contact_jid = this.model.get('jid');
|
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;
|
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) {
|
if (_.filter(results, 'length').length) {
|
||||||
const html = templates_spoiler_button_html__WEBPACK_IMPORTED_MODULE_16___default()(this.model.toJSON());
|
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.registerPresenceHandler = function () {
|
||||||
_converse.unregisterPresenceHandler();
|
_converse.unregisterPresenceHandler();
|
||||||
|
|
||||||
_converse.presence_ref = _converse.connection.addHandler(function (presence) {
|
_converse.presence_ref = _converse.connection.addHandler(presence => {
|
||||||
_converse.roster.presenceHandler(presence);
|
_converse.roster.presenceHandler(presence);
|
||||||
|
|
||||||
return true;
|
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({
|
_converse.Presence = Backbone.Model.extend({
|
||||||
defaults() {
|
defaults: {
|
||||||
return {
|
'show': 'offline'
|
||||||
'show': 'offline',
|
},
|
||||||
'resources': {}
|
|
||||||
};
|
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() {
|
getHighestPriorityResource() {
|
||||||
@ -67857,15 +67879,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||||||
* If multiple resources have the same priority, take the
|
* If multiple resources have the same priority, take the
|
||||||
* latest one.
|
* latest one.
|
||||||
*/
|
*/
|
||||||
const resources = this.get('resources');
|
return this.resources.sortBy(r => `${r.get('priority')}-${r.get('timestamp')}`).reverse()[0];
|
||||||
|
|
||||||
if (_.isObject(resources) && _.size(resources)) {
|
|
||||||
const val = _.flow(_.values, _.partial(_.sortBy, _, ['priority', 'timestamp']), _.reverse)(resources)[0];
|
|
||||||
|
|
||||||
if (!_.isUndefined(val)) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addResource(presence) {
|
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).
|
* Also updates the presence if the resource has higher priority (and is newer).
|
||||||
*/
|
*/
|
||||||
const jid = presence.getAttribute('from'),
|
const jid = presence.getAttribute('from'),
|
||||||
show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
|
name = Strophe.getResourceFromJid(jid),
|
||||||
resource = Strophe.getResourceFromJid(jid),
|
|
||||||
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
|
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
|
||||||
timestamp = _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
|
priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0,
|
||||||
let priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
|
resource = this.resources.get(name),
|
||||||
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
|
settings = {
|
||||||
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
|
'name': name,
|
||||||
resources[resource] = {
|
'priority': _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
|
||||||
'name': resource,
|
'show': _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
|
||||||
'priority': priority,
|
'timestamp': _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format()
|
||||||
'show': show,
|
|
||||||
'timestamp': timestamp
|
|
||||||
};
|
};
|
||||||
const changed = {
|
|
||||||
'resources': resources
|
|
||||||
};
|
|
||||||
const hpr = this.getHighestPriorityResource();
|
|
||||||
|
|
||||||
if (priority == hpr.priority && timestamp == hpr.timestamp) {
|
if (resource) {
|
||||||
// Only set the "global" presence if this is the newest resource
|
resource.save(settings);
|
||||||
// with the highest priority
|
} else {
|
||||||
changed.show = show;
|
this.resources.create(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save(changed);
|
|
||||||
return resources;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
removeResource(resource) {
|
removeResource(name) {
|
||||||
/* Remove the passed in resource from the resources map.
|
/* Remove the passed in resource from the resources map.
|
||||||
*
|
*
|
||||||
* Also redetermines the presence given that there's one less
|
* Also redetermines the presence given that there's one less
|
||||||
* resource.
|
* resource.
|
||||||
*/
|
*/
|
||||||
let resources = this.get('resources');
|
const resource = this.resources.get(name);
|
||||||
|
|
||||||
if (!_.isObject(resources)) {
|
if (resource) {
|
||||||
resources = {};
|
resource.destroy();
|
||||||
} else {
|
|
||||||
delete resources[resource];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save({
|
|
||||||
'resources': resources,
|
|
||||||
'show': _.propertyOf(this.getHighestPriorityResource())('show') || 'offline'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -68686,8 +68683,16 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||||||
|
|
||||||
_converse.api.listen.on('afterTearDown', () => {
|
_converse.api.listen.on('afterTearDown', () => {
|
||||||
if (_converse.presences) {
|
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 => {
|
_converse.api.listen.on('statusInitialized', reconnecting => {
|
||||||
if (!reconnecting) {
|
if (!reconnecting) {
|
||||||
_converse.presences = new _converse.Presences();
|
_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);
|
_converse.emit('presencesInitialized', reconnecting);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -68723,9 +68729,9 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||||||
|
|
||||||
_converse.roster.onConnected();
|
_converse.roster.onConnected();
|
||||||
|
|
||||||
_converse.populateRoster(reconnecting);
|
|
||||||
|
|
||||||
_converse.registerPresenceHandler();
|
_converse.registerPresenceHandler();
|
||||||
|
|
||||||
|
_converse.populateRoster(reconnecting);
|
||||||
});
|
});
|
||||||
/************************ API ************************/
|
/************************ API ************************/
|
||||||
// API methods only available to plugins
|
// API methods only available to plugins
|
||||||
|
131
spec/presence.js
131
spec/presence.js
@ -125,9 +125,9 @@
|
|||||||
|
|
||||||
test_utils.openControlBox();
|
test_utils.openControlBox();
|
||||||
test_utils.createContacts(_converse, 'current'); // Create some contacts so that we can test positioning
|
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';
|
const contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||||
var contact = _converse.roster.get(contact_jid);
|
const contact = _converse.roster.get(contact_jid);
|
||||||
var stanza = $(
|
let stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
' to="dummy@localhost/converse.js-21770972"'+
|
' to="dummy@localhost/converse.js-21770972"'+
|
||||||
' from="'+contact_jid+'/priority-1-resource">'+
|
' from="'+contact_jid+'/priority-1-resource">'+
|
||||||
@ -141,9 +141,9 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(contact.presence.get('show')).toBe('online');
|
expect(contact.presence.get('show')).toBe('online');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(1);
|
expect(contact.presence.resources.length).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<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"/>'+
|
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="'+contact_jid+'/priority-0-resource"/>'+
|
||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
|
expect(contact.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.resources.length).toBe(2);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
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 = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -172,14 +173,14 @@
|
|||||||
' <show>dnd</show>'+
|
' <show>dnd</show>'+
|
||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
expect(contact.presence.get('show')).toBe('dnd');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(3);
|
expect(contact.presence.resources.length).toBe(3);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -190,15 +191,15 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(4);
|
expect(contact.presence.resources.length).toBe(4);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.get('resources')['priority-3-resource']['priority']).toBe(3);
|
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
|
||||||
expect(contact.presence.get('resources')['priority-3-resource']['show']).toBe('away');
|
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -210,17 +211,17 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(5);
|
expect(contact.presence.resources.length).toBe(5);
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.get('resources')['priority-3-resource']['priority']).toBe(3);
|
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
|
||||||
expect(contact.presence.get('resources')['priority-3-resource']['show']).toBe('away');
|
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -230,15 +231,15 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(4);
|
expect(contact.presence.resources.length).toBe(4);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['priority']).toBe(2);
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
expect(contact.presence.get('resources')['priority-2-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -248,13 +249,13 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(3);
|
expect(contact.presence.resources.length).toBe(3);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-1-resource']['show']).toBe('online');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -264,11 +265,11 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(2);
|
expect(contact.presence.resources.length).toBe(2);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['priority']).toBe(1);
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('resources')['older-priority-1-resource']['show']).toBe('dnd');
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -278,9 +279,9 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('xa');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('xa');
|
||||||
expect(_.keys(contact.presence.get('resources')).length).toBe(1);
|
expect(contact.presence.resources.length).toBe(1);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['priority']).toBe(0);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.get('resources')['priority-0-resource']['show']).toBe('xa');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
|
|
||||||
stanza = $(
|
stanza = $(
|
||||||
'<presence xmlns="jabber:client"'+
|
'<presence xmlns="jabber:client"'+
|
||||||
@ -290,7 +291,7 @@
|
|||||||
'</presence>');
|
'</presence>');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('offline');
|
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();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -431,13 +431,14 @@ converse.plugins.add('converse-chatview', {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const contact_jid = this.model.get('jid');
|
const contact_jid = this.model.get('jid');
|
||||||
const resources = this.model.presence.get('resources');
|
if (this.model.presence.resources.length === 0) {
|
||||||
if (_.isEmpty(resources)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const results = await Promise.all(_.map(_.keys(resources),
|
const results = await Promise.all(
|
||||||
resource => _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${resource}`)
|
this.model.presence.resources.map(
|
||||||
));
|
res => _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${res.get('name')}`)
|
||||||
|
)
|
||||||
|
);
|
||||||
if (_.filter(results, 'length').length) {
|
if (_.filter(results, 'length').length) {
|
||||||
const html = tpl_spoiler_button(this.model.toJSON());
|
const html = tpl_spoiler_button(this.model.toJSON());
|
||||||
if (_converse.visible_toolbar_buttons.emoji) {
|
if (_converse.visible_toolbar_buttons.emoji) {
|
||||||
|
@ -38,8 +38,7 @@ converse.plugins.add('converse-roster', {
|
|||||||
|
|
||||||
_converse.registerPresenceHandler = function () {
|
_converse.registerPresenceHandler = function () {
|
||||||
_converse.unregisterPresenceHandler();
|
_converse.unregisterPresenceHandler();
|
||||||
_converse.presence_ref = _converse.connection.addHandler(
|
_converse.presence_ref = _converse.connection.addHandler(presence => {
|
||||||
function (presence) {
|
|
||||||
_converse.roster.presenceHandler(presence);
|
_converse.roster.presenceHandler(presence);
|
||||||
return true;
|
return true;
|
||||||
}, null, 'presence', null);
|
}, 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({
|
_converse.Presence = Backbone.Model.extend({
|
||||||
defaults () {
|
defaults: {
|
||||||
return {
|
'show': 'offline'
|
||||||
'show': 'offline',
|
},
|
||||||
'resources': {}
|
|
||||||
|
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
|
* If multiple resources have the same priority, take the
|
||||||
* latest one.
|
* latest one.
|
||||||
*/
|
*/
|
||||||
const resources = this.get('resources');
|
return this.resources.sortBy(r => `${r.get('priority')}-${r.get('timestamp')}`).reverse()[0];
|
||||||
if (_.isObject(resources) && _.size(resources)) {
|
|
||||||
const val = _.flow(
|
|
||||||
_.values,
|
|
||||||
_.partial(_.sortBy, _, ['priority', 'timestamp']),
|
|
||||||
_.reverse
|
|
||||||
)(resources)[0];
|
|
||||||
if (!_.isUndefined(val)) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addResource (presence) {
|
addResource (presence) {
|
||||||
@ -137,52 +142,35 @@ converse.plugins.add('converse-roster', {
|
|||||||
* Also updates the presence if the resource has higher priority (and is newer).
|
* Also updates the presence if the resource has higher priority (and is newer).
|
||||||
*/
|
*/
|
||||||
const jid = presence.getAttribute('from'),
|
const jid = presence.getAttribute('from'),
|
||||||
show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
|
name = Strophe.getResourceFromJid(jid),
|
||||||
resource = Strophe.getResourceFromJid(jid),
|
|
||||||
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
|
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
|
||||||
timestamp = _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
|
priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0,
|
||||||
|
resource = this.resources.get(name),
|
||||||
let priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
|
settings = {
|
||||||
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
|
'name': name,
|
||||||
|
'priority': _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
|
||||||
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
|
'show': _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
|
||||||
resources[resource] = {
|
'timestamp': _.isNil(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format()
|
||||||
'name': resource,
|
};
|
||||||
'priority': priority,
|
if (resource) {
|
||||||
'show': show,
|
resource.save(settings);
|
||||||
'timestamp': timestamp
|
} else {
|
||||||
};
|
this.resources.create(settings);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
this.save(changed);
|
|
||||||
return resources;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
removeResource (resource) {
|
removeResource (name) {
|
||||||
/* Remove the passed in resource from the resources map.
|
/* Remove the passed in resource from the resources map.
|
||||||
*
|
*
|
||||||
* Also redetermines the presence given that there's one less
|
* Also redetermines the presence given that there's one less
|
||||||
* resource.
|
* resource.
|
||||||
*/
|
*/
|
||||||
let resources = this.get('resources');
|
const resource = this.resources.get(name);
|
||||||
if (!_.isObject(resources)) {
|
if (resource) {
|
||||||
resources = {};
|
resource.destroy();
|
||||||
} else {
|
|
||||||
delete resources[resource];
|
|
||||||
}
|
}
|
||||||
this.save({
|
}
|
||||||
'resources': resources,
|
|
||||||
'show': _.propertyOf(
|
|
||||||
this.getHighestPriorityResource())('show') || 'offline'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -847,7 +835,10 @@ converse.plugins.add('converse-roster', {
|
|||||||
|
|
||||||
_converse.api.listen.on('afterTearDown', () => {
|
_converse.api.listen.on('afterTearDown', () => {
|
||||||
if (_converse.presences) {
|
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) => {
|
_converse.api.listen.on('statusInitialized', (reconnecting) => {
|
||||||
if (!reconnecting) {
|
if (!reconnecting) {
|
||||||
_converse.presences = new _converse.Presences();
|
_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);
|
_converse.emit('presencesInitialized', reconnecting);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -879,8 +870,8 @@ converse.plugins.add('converse-roster', {
|
|||||||
_converse.initRoster();
|
_converse.initRoster();
|
||||||
}
|
}
|
||||||
_converse.roster.onConnected();
|
_converse.roster.onConnected();
|
||||||
_converse.populateRoster(reconnecting);
|
|
||||||
_converse.registerPresenceHandler();
|
_converse.registerPresenceHandler();
|
||||||
|
_converse.populateRoster(reconnecting);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user