diff --git a/.eslintrc.json b/.eslintrc.json
index 9c2f8092d..f9c59d290 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -59,7 +59,7 @@
"dot-notation": [
"error",
{
- "allowKeywords": false
+ "allowKeywords": true
}
],
"eol-last": "error",
diff --git a/CHANGES.md b/CHANGES.md
index 8cc69437b..2a050ac52 100755
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,11 @@
## 3.2.0 (Unreleased)
+### New Plugins
+- New plugin `converse-disco` which replaces the original support for
+ [XEP-0030](https://xmpp.org/extensions/xep-0030.html) and which has been
+ refactored to allow features for multiple entities to be stored. [jcbrand]
+
### New features and improvements
- Add support for Emojis (either native, or via Emojione). [jcbrand]
- Add JID validation in the contact add form. [jcbrand]
diff --git a/spec/converse.js b/spec/converse.js
index 6fbd5b832..bb90c581f 100644
--- a/spec/converse.js
+++ b/spec/converse.js
@@ -53,7 +53,11 @@
describe("A chat state indication", function () {
- it("are sent out when the client becomes or stops being idle", mock.initConverse(function (_converse) {
+ it("are sent out when the client becomes or stops being idle",
+ mock.initConverseWithPromises(
+ null, ['discoInitialized'], {},
+ function (done, _converse) {
+
spyOn(_converse, 'sendCSI').and.callThrough();
var sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
@@ -61,7 +65,7 @@
});
var i = 0;
_converse.idle_seconds = 0; // Usually initialized by registerIntervalHandler
- _converse.features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
+ _converse.disco_entities.get(_converse.domain).features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
_converse.csi_waiting_time = 3; // The relevant config option
while (i <= _converse.csi_waiting_time) {
@@ -78,10 +82,10 @@
expect(sent_stanza.toLocaleString()).toBe(
""
);
-
// Reset values
_converse.csi_waiting_time = 0;
- _converse.features['urn:xmpp:csi:0'] = false;
+ _converse.disco_entities.get(_converse.domain).features['urn:xmpp:csi:0'] = false;
+ done();
}));
});
diff --git a/spec/disco.js b/spec/disco.js
index 2aa318a78..fa8146cec 100644
--- a/spec/disco.js
+++ b/spec/disco.js
@@ -11,11 +11,16 @@
describe("Service Discovery", function () {
describe("Whenever converse.js discovers a new server feature", function () {
- it("emits the serviceDiscovered event", mock.initConverse(function (_converse) {
+ it("emits the serviceDiscovered event",
+ mock.initConverseWithPromises(
+ null, ['discoInitialized'], {},
+ function (done, _converse) {
+
sinon.spy(_converse, 'emit');
- _converse.features.create({'var': Strophe.NS.MAM});
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
expect(_converse.emit.called).toBe(true);
expect(_converse.emit.args[0][1].get('var')).toBe(Strophe.NS.MAM);
+ done();
}));
});
});
diff --git a/spec/mam.js b/spec/mam.js
index 530ab7755..240f45635 100644
--- a/spec/mam.js
+++ b/spec/mam.js
@@ -15,20 +15,25 @@
describe("The archive.query API", function () {
- it("can be used to query for all archived messages", mock.initConverse(function (_converse) {
+ it("can be used to query for all archived messages",
+ mock.initConverseWithPromises(
+ null, ['discoInitialized'], {},
+ function (done, _converse) {
+
var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
_converse.api.archive.query();
var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
expect(sent_stanza.toString()).toBe(
"");
+ done();
}));
it("can be used to query for all messages to/from a particular JID", mock.initConverse(function (_converse) {
@@ -38,8 +43,8 @@
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
_converse.api.archive.query({'with':'juliet@capulet.lit'});
var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
@@ -66,8 +71,8 @@
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var start = '2010-06-07T00:00:00Z';
var end = '2010-07-07T13:23:54Z';
@@ -97,8 +102,8 @@
}));
it("throws a TypeError if an invalid date is provided", mock.initConverse(function (_converse) {
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
expect(_.partial(_converse.api.archive.query, {'start': 'not a real date'})).toThrow(
new TypeError('archive.query: invalid date provided for: start')
@@ -112,8 +117,8 @@
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({'start': start});
@@ -141,8 +146,8 @@
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({'start': start, 'max':10});
@@ -173,8 +178,8 @@
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({
@@ -210,8 +215,8 @@
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
_converse.api.archive.query({'before': '', 'max':10});
var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
@@ -237,8 +242,8 @@
// and pass it in. However, in the callback method an RSM object is
// returned which can be reused for easy paging. This test is
// more for that usecase.
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ;
@@ -247,7 +252,7 @@
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
var rsm = new Strophe.RSM({'max': '10'});
- rsm['with'] = 'romeo@montague.lit';
+ rsm['with'] = 'romeo@montague.lit'; // eslint-disable-line dot-notation
rsm.start = '2010-06-07T00:00:00Z';
_converse.api.archive.query(rsm);
@@ -275,8 +280,8 @@
}));
it("accepts a callback function, which it passes the messages and a Strophe.RSM object", mock.initConverse(function (_converse) {
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
- _converse.features.create({'var': Strophe.NS.MAM});
+ if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
+ _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ;
@@ -351,7 +356,7 @@
expect(args[0].length).toBe(2);
expect(args[0][0].outerHTML).toBe(msg1.nodeTree.outerHTML);
expect(args[0][1].outerHTML).toBe(msg2.nodeTree.outerHTML);
- expect(args[1]['with']).toBe('romeo@capulet.lit');
+ expect(args[1]['with']).toBe('romeo@capulet.lit'); // eslint-disable-line dot-notation
expect(args[1].max).toBe('10');
expect(args[1].count).toBe('16');
expect(args[1].first).toBe('23452-4534-1');
@@ -376,7 +381,7 @@
'var': Strophe.NS.MAM
});
spyOn(feature, 'save').and.callFake(feature.set); // Save will complain about a url not being set
- _converse.features.onFeatureAdded(feature);
+ _converse.disco_entities.get(_converse.domain).features.onFeatureAdded(feature);
expect(_converse.connection.sendIQ).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe(
@@ -430,7 +435,7 @@
.c('never').up();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(feature.save).toHaveBeenCalled();
- expect(feature.get('preferences')['default']).toBe('never');
+ expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation
// Restore
_converse.message_archiving = 'never';
diff --git a/src/config.js b/src/config.js
index e958c044f..6623f952f 100644
--- a/src/config.js
+++ b/src/config.js
@@ -55,6 +55,7 @@ require.config({
"converse-chatview": "src/converse-chatview",
"converse-controlbox": "src/converse-controlbox",
"converse-core": "src/converse-core",
+ "converse-disco": "src/converse-disco",
"converse-dragresize": "src/converse-dragresize",
"converse-headline": "src/converse-headline",
"converse-inverse": "src/converse-inverse",
diff --git a/src/converse-core.js b/src/converse-core.js
index d232fbb55..3901102ee 100755
--- a/src/converse-core.js
+++ b/src/converse-core.js
@@ -16,7 +16,6 @@
"strophe",
"pluggable",
"backbone.noconflict",
- "strophe.disco",
"backbone.browserStorage",
"backbone.overview",
], factory);
@@ -59,6 +58,7 @@
'converse-chatview',
'converse-controlbox',
'converse-core',
+ 'converse-disco',
'converse-dragresize',
'converse-headline',
'converse-mam',
@@ -794,16 +794,11 @@
// If there's no xmppstatus obj, then we were never connected to
// begin with, so we set reconnecting to false.
reconnecting = _.isUndefined(_converse.xmppstatus) ? false : reconnecting;
-
if (reconnecting) {
_converse.onStatusInitialized(true);
_converse.emit('reconnected');
} else {
- // There might be some open chat boxes. We don't
- // know whether these boxes are of the same account or not, so we
- // close them now.
_converse.chatboxviews.closeAllChatBoxes();
- _converse.features = new _converse.Features();
_converse.initStatus()
.then(
_.partial(_converse.onStatusInitialized, false),
@@ -1866,88 +1861,6 @@
}
});
- this.Features = Backbone.Collection.extend({
- /* Service Discovery
- * -----------------
- * This collection stores Feature Models, representing features
- * provided by available XMPP entities (e.g. servers)
- * See XEP-0030 for more details: http://xmpp.org/extensions/xep-0030.html
- * All features are shown here: http://xmpp.org/registrar/disco-features.html
- */
- model: Backbone.Model,
- initialize () {
- this.addClientIdentities().addClientFeatures();
- this.browserStorage = new Backbone.BrowserStorage[_converse.storage](
- b64_sha1(`converse.features${_converse.bare_jid}`)
- );
- this.on('add', this.onFeatureAdded, this);
- this.fetchFeatures();
- },
-
- fetchFeatures () {
- if (this.browserStorage.records.length === 0) {
- // browserStorage is empty, so we've likely never queried this
- // domain for features yet
- _converse.connection.disco.info(_converse.domain, null, this.onInfo.bind(this));
- _converse.connection.disco.items(_converse.domain, null, this.onItems.bind(this));
- } else {
- this.fetch({add:true});
- }
- },
-
- onFeatureAdded (feature) {
- _converse.emit('serviceDiscovered', feature);
- },
-
- addClientIdentities () {
- /* See http://xmpp.org/registrar/disco-categories.html
- */
- _converse.connection.disco.addIdentity('client', 'web', 'Converse.js');
- return this;
- },
-
- addClientFeatures () {
- /* The strophe.disco.js plugin keeps a list of features which
- * it will advertise to any #info queries made to it.
- *
- * See: http://xmpp.org/extensions/xep-0030.html#info
- */
- _converse.connection.disco.addFeature(Strophe.NS.BOSH);
- _converse.connection.disco.addFeature(Strophe.NS.CHATSTATES);
- _converse.connection.disco.addFeature(Strophe.NS.DISCO_INFO);
- _converse.connection.disco.addFeature(Strophe.NS.ROSTERX); // Limited support
- if (_converse.message_carbons) {
- _converse.connection.disco.addFeature(Strophe.NS.CARBONS);
- }
- return this;
- },
-
- onItems (stanza) {
- _.each(stanza.querySelectorAll('query item'), (item) => {
- _converse.connection.disco.info(
- item.getAttribute('jid'),
- null,
- this.onInfo.bind(this));
- });
- },
-
- onInfo (stanza) {
- if ((sizzle('identity[category=server][type=im]', stanza).length === 0) &&
- (sizzle('identity[category=conference][type=text]', stanza).length === 0)) {
- // This isn't an IM server component
- return;
- }
- _.forEach(stanza.querySelectorAll('feature'), (feature) => {
- const namespace = feature.getAttribute('var');
- this[namespace] = true;
- this.create({
- 'var': namespace,
- 'from': stanza.getAttribute('from')
- });
- });
- }
- });
-
this.setUpXMLLogging = function () {
Strophe.log = function (level, msg) {
_converse.log(msg, level);
@@ -2165,16 +2078,13 @@
/* Remove those views which are only allowed with a valid
* connection.
*/
+ _converse.emit('beforeTearDown');
this.unregisterPresenceHandler();
if (this.roster) {
this.roster.off().reset(); // Removes roster contacts
}
this.chatboxes.remove(); // Don't call off(), events won't get re-registered upon reconnect.
delete this.chatboxes.browserStorage;
- if (this.features) {
- this.features.reset();
- this.features.browserStorage._clear();
- }
this.session.destroy();
window.removeEventListener('click', _converse.onUserActivity);
window.removeEventListener('focus', _converse.onUserActivity);
@@ -2182,6 +2092,7 @@
window.removeEventListener('mousemove', _converse.onUserActivity);
window.removeEventListener(unloadevent, _converse.onUserActivity);
window.clearInterval(_converse.everySecondTrigger);
+ _converse.emit('afterTearDown');
return this;
};
diff --git a/src/converse-disco.js b/src/converse-disco.js
index 3194e334a..645a30a46 100644
--- a/src/converse-disco.js
+++ b/src/converse-disco.js
@@ -84,7 +84,12 @@
* All features are shown here: http://xmpp.org/registrar/disco-features.html
*/
model: Backbone.Model,
- initialize (jid) {
+
+ initialize (settings) {
+ const jid = settings.jid;
+ if (_.isNil(jid)) {
+ throw new Error('DiscoEntity must be instantiated with a JID');
+ }
this.addClientIdentities().addClientFeatures();
this.browserStorage = new Backbone.BrowserStorage[_converse.storage](
b64_sha1(`converse.features-${jid}`)
@@ -158,9 +163,11 @@
}
});
- _converse.api.waitUntil('connected').then(() => {
+ function initializeDisco () {
_converse.disco_entities = new _converse.DiscoEntities();
- });
+ }
+ _converse.api.listen.on('reconnected', initializeDisco);
+ _converse.api.listen.on('connected', initializeDisco);
_converse.api.listen.on('beforeTearDown', () => {
if (_converse.disco_entities) {
diff --git a/src/converse-mam.js b/src/converse-mam.js
index 30fcf9e3d..4549acc6c 100644
--- a/src/converse-mam.js
+++ b/src/converse-mam.js
@@ -11,6 +11,7 @@
(function (root, factory) {
define(["jquery.noconflict",
"converse-core",
+ "converse-disco",
"converse-chatview", // Could be made a soft dependency
"converse-muc", // Could be made a soft dependency
"strophe.rsm"
@@ -31,15 +32,6 @@
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
-
- Features: {
- addClientFeatures () {
- const { _converse } = this.__super__;
- _converse.connection.disco.addFeature(Strophe.NS.MAM);
- return this.__super__.addClientFeatures.apply(this, arguments);
- }
- },
-
ChatBox: {
getMessageAttributes ($message, $delay, original_stanza) {
const attrs = this.__super__.getMessageAttributes.apply(this, arguments);
@@ -60,7 +52,8 @@
afterMessagesFetched () {
const { _converse } = this.__super__;
if (this.disable_mam ||
- !_converse.features.findWhere({'var': Strophe.NS.MAM})) {
+ !_converse.disco_entities.get(_converse.domain)
+ .features.findWhere({'var': Strophe.NS.MAM})) {
return this.__super__.afterMessagesFetched.apply(this, arguments);
}
if (!this.model.get('mam_initialized') &&
@@ -83,7 +76,9 @@
* box, so that they are displayed inside it.
*/
const { _converse } = this.__super__;
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
+ if (!_converse.disco_entities.get(_converse.domain)
+ .features.findWhere({'var': Strophe.NS.MAM})) {
+
_converse.log(
"Attempted to fetch archived messages but this "+
"user's server doesn't support XEP-0313",
@@ -167,7 +162,9 @@
* so that they are displayed inside it.
*/
const { _converse } = this.__super__;
- if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
+ if (!_converse.disco_entities.get(_converse.domain)
+ .features.findWhere({'var': Strophe.NS.MAM})) {
+
_converse.log(
"Attempted to fetch archived messages but this "+
"user's server doesn't support XEP-0313",
@@ -237,12 +234,12 @@
const queryid = _converse.connection.getUniqueId();
const attrs = {'type':'set'};
if (!_.isUndefined(options) && options.groupchat) {
- if (!options['with']) {
+ if (!options['with']) { // eslint-disable-line dot-notation
throw new Error(
'You need to specify a "with" value containing '+
'the chat room JID, when querying groupchat messages.');
}
- attrs.to = options['with'];
+ attrs.to = options['with']; // eslint-disable-line dot-notation
}
const stanza = $iq(attrs).c('query', {'xmlns':Strophe.NS.MAM, 'queryid':queryid});
if (!_.isUndefined(options)) {
@@ -250,8 +247,9 @@
.c('field', {'var':'FORM_TYPE', 'type': 'hidden'})
.c('value').t(Strophe.NS.MAM).up().up();
- if (options['with'] && !options.groupchat) {
- stanza.c('field', {'var':'with'}).c('value').t(options['with']).up().up();
+ if (options['with'] && !options.groupchat) { // eslint-disable-line dot-notation
+ stanza.c('field', {'var':'with'}).c('value')
+ .t(options['with']).up().up(); // eslint-disable-line dot-notation
}
_.each(['start', 'end'], function (t) {
if (options[t]) {
@@ -352,11 +350,11 @@
}
};
-
- const onFeatureAdded = function (feature) {
+ /* Event handlers */
+ _converse.on('serviceDiscovered', (feature) => {
const prefs = feature.get('preferences') || {};
if (feature.get('var') === Strophe.NS.MAM &&
- prefs['default'] !== _converse.message_archiving &&
+ prefs['default'] !== _converse.message_archiving && // eslint-disable-line dot-notation
!_.isUndefined(_converse.message_archiving) ) {
// Ask the server for archiving preferences
_converse.connection.sendIQ(
@@ -365,8 +363,11 @@
_.partial(_converse.onMAMError, feature)
);
}
- };
- _converse.on('serviceDiscovered', onFeatureAdded.bind(_converse.features));
+ });
+
+ _converse.on('addClientFeatures', () => {
+ _converse.connection.disco.addFeature(Strophe.NS.MAM);
+ });
}
});
}));
diff --git a/src/converse-muc.js b/src/converse-muc.js
index fa65728ed..8a87fe9d2 100755
--- a/src/converse-muc.js
+++ b/src/converse-muc.js
@@ -32,7 +32,8 @@
"tpl!room_panel",
"tpl!spinner",
"awesomplete",
- "converse-chatview"
+ "converse-chatview",
+ "converse-disco"
], factory);
}(this, function (
$,
@@ -130,19 +131,6 @@
this.__super__._tearDown.call(this, arguments);
},
- Features: {
- addClientFeatures () {
- const { _converse } = this.__super__;
- this.__super__.addClientFeatures.apply(this, arguments);
- if (_converse.allow_muc_invitations) {
- _converse.connection.disco.addFeature('jabber:x:conference'); // Invites
- }
- if (_converse.allow_muc) {
- _converse.connection.disco.addFeature(Strophe.NS.MUC);
- }
- }
- },
-
ChatBoxes: {
model (attrs, options) {
const { _converse } = this.__super__;
@@ -182,6 +170,33 @@
}
},
+ featureAdded (feature) {
+ const { _converse } = this.__super__;
+ if ((feature.get('var') === Strophe.NS.MUC) && (_converse.allow_muc)) {
+ this.setMUCDomain(feature.get('from'));
+ }
+ },
+
+ getMUCDomainFromDisco () {
+ /* Check whether service discovery for the user's domain
+ * returned MUC information and use that to automatically
+ * set the MUC domain for the "Rooms" panel of the
+ * controlbox.
+ */
+ const { _converse } = this.__super__;
+ _converse.api.waitUntil('discoInitialized').then(() => {
+ _converse.api.listen.on('serviceDiscovered', this.featureAdded, this);
+ // Features could have been added before the controlbox was
+ // initialized. We're only interested in MUC
+ const feature = _converse.disco_entities[_converse.domain].features.findWhere({
+ 'var': Strophe.NS.MUC
+ });
+ if (feature) {
+ this.featureAdded(feature);
+ }
+ });
+ },
+
onConnected () {
const { _converse } = this.__super__;
this.__super__.onConnected.apply(this, arguments);
@@ -189,34 +204,20 @@
return;
}
if (_.isUndefined(_converse.muc_domain)) {
- _converse.features.off('add', this.featureAdded, this);
- _converse.features.on('add', this.featureAdded, this);
- // Features could have been added before the controlbox was
- // initialized. We're only interested in MUC
- const feature = _converse.features.findWhere({
- 'var': Strophe.NS.MUC
- });
- if (feature) {
- this.featureAdded(feature);
- }
+ this.getMUCDomainFromDisco();
} else {
this.setMUCDomain(_converse.muc_domain);
}
},
setMUCDomain (domain) {
+ const { _converse } = this.__super__;
+ _converse.muc_domain = domain;
this.roomspanel.model.save({'muc_domain': domain});
const $server= this.$el.find('input.new-chatroom-server');
if (!$server.is(':focus')) {
$server.val(this.roomspanel.model.get('muc_domain'));
}
- },
-
- featureAdded (feature) {
- const { _converse } = this.__super__;
- if ((feature.get('var') === Strophe.NS.MUC) && (_converse.allow_muc)) {
- this.setMUCDomain(feature.get('from'));
- }
}
},
@@ -1974,7 +1975,7 @@
return false;
} else {
return this.model.messages.where({
- 'sender': this.model.get('nick'),
+ 'sender': 'me',
'message': this.model.getMessageBody(message)
}).filter(
(msg) => Math.abs(moment(msg.get('time')).diff(moment.unix(ts))) < 2000
@@ -2778,7 +2779,17 @@
}
});
- function reconnectToChatRooms () {
+ /* Event handlers */
+ _converse.on('addClientFeatures', () => {
+ if (_converse.allow_muc) {
+ _converse.connection.disco.addFeature(Strophe.NS.MUC);
+ }
+ if (_converse.allow_muc_invitations) {
+ _converse.connection.disco.addFeature('jabber:x:conference'); // Invites
+ }
+ });
+
+ _converse.on('reconnected', function reconnectToChatRooms () {
/* Upon a reconnection event from converse, join again
* all the open chat rooms.
*/
@@ -2790,8 +2801,7 @@
view.fetchMessages();
}
});
- }
- _converse.on('reconnected', reconnectToChatRooms);
+ });
function disconnectChatRooms () {
/* When disconnecting, or reconnecting, mark all chat rooms as
diff --git a/src/converse-ping.js b/src/converse-ping.js
index a3e1c1a14..9482f46e5 100644
--- a/src/converse-ping.js
+++ b/src/converse-ping.js
@@ -34,7 +34,7 @@
// However, some servers don't advertise while still keeping the
// connection option due to pings.
//
- // var feature = _converse.features.findWhere({'var': Strophe.NS.PING});
+ // var feature = _converse.disco_entities[_converse.domain].features.findWhere({'var': Strophe.NS.PING});
_converse.lastStanzaDate = new Date();
if (_.isNil(jid)) {
jid = Strophe.getDomainFromJid(_converse.bare_jid);
diff --git a/src/converse-vcard.js b/src/converse-vcard.js
index 3eca64404..290e7f60f 100644
--- a/src/converse-vcard.js
+++ b/src/converse-vcard.js
@@ -21,16 +21,6 @@
//
// New functions which don't exist yet can also be added.
- Features: {
- addClientFeatures () {
- const { _converse } = this.__super__;
- this.__super__.addClientFeatures.apply(this, arguments);
- if (_converse.use_vcards) {
- _converse.connection.disco.addFeature(Strophe.NS.VCARD);
- }
- }
- },
-
RosterContacts: {
createRequestingContact (presence) {
const { _converse } = this.__super__;
@@ -50,7 +40,6 @@
}
},
-
initialize () {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
@@ -135,6 +124,13 @@
}
};
+ /* Event handlers */
+ _converse.on('addClientFeatures', () => {
+ if (_converse.use_vcards) {
+ _converse.connection.disco.addFeature(Strophe.NS.VCARD);
+ }
+ });
+
const updateVCardForChatBox = function (chatbox) {
if (!_converse.use_vcards) { return; }
const jid = chatbox.model.get('jid'),
@@ -161,7 +157,6 @@
};
_converse.on('chatBoxInitialized', updateVCardForChatBox);
-
const onContactAdd = function (contact) {
if (!contact.get('vcard_updated')) {
// This will update the vcard, which triggers a change
@@ -173,7 +168,7 @@
_converse.roster.on("add", onContactAdd);
});
- const fetchOwnVCard = function () {
+ _converse.on('statusInitialized', function fetchOwnVCard () {
if (_converse.xmppstatus.get('fullname') === undefined) {
_converse.getVCard(
null, // No 'to' attr when getting one's own vCard
@@ -182,8 +177,7 @@
}
);
}
- };
- _converse.on('statusInitialized', fetchOwnVCard);
+ });
}
});
}));