Commit 55fce912 authored by JC Brand's avatar JC Brand Committed by GitHub

Merge branch 'master' into async-await

parents 35b7dbe3 c583678c
# Changelog # Changelog
## 4.1.0 (Unreleased) ## 4.0.4 (Unreleased)
- Use [Lerna](https://lernajs.io/) to create the @converse/headless package - Use [Lerna](https://lernajs.io/) to create the @converse/headless package
- Use ES2015 modules instead of UMD. - Use ES2015 modules instead of UMD.
- #1257: Prefer 'probably' over 'maybe' when evaluating audio play support. - #1257 Prefer 'probably' over 'maybe' when evaluating audio play support.
- #1261 File upload not working
## 4.0.3 (2018-10-22) ## 4.0.3 (2018-10-22)
......
This diff is collapsed.
...@@ -3178,16 +3178,13 @@ ...@@ -3178,16 +3178,13 @@
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz", "resolved": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz",
"integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=", "integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=",
"dev": true,
"requires": { "requires": {
"underscore": ">=1.8.3" "underscore": ">=1.8.3"
} }
}, },
"backbone.browserStorage": { "backbone.browserStorage": {
"version": "0.0.4", "version": "github:jcbrand/Backbone.browserStorage#03bfa13f68b71f97be361840adc5a5064f57b47e",
"resolved": "https://registry.npmjs.org/backbone.browserStorage/-/backbone.browserStorage-0.0.4.tgz", "from": "github:jcbrand/Backbone.browserStorage#03bfa13f68b71f97be361840adc5a5064f57b47e",
"integrity": "sha512-4LvDP2IkOu9Nt6kj6ft4moKmqKqm3c0WY3c/aie0Cf374wjFuO7vCh/afcKdu1YSuVsryM8yH90/J7yqWbaPHw==",
"dev": true,
"requires": { "requires": {
"backbone": "~1.x.x", "backbone": "~1.x.x",
"underscore": ">=1.4.0" "underscore": ">=1.4.0"
...@@ -15220,8 +15217,7 @@ ...@@ -15220,8 +15217,7 @@
"underscore": { "underscore": {
"version": "1.8.3", "version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
"dev": true
}, },
"underscore-contrib": { "underscore-contrib": {
"version": "0.3.0", "version": "0.3.0",
......
...@@ -1020,24 +1020,21 @@ ...@@ -1020,24 +1020,21 @@
it("will clear any other chat status notifications", it("will clear any other chat status notifications",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched'); _converse.emit('rosterContactsFetched');
test_utils.openControlBox(); test_utils.openControlBox();
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
let view;
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
spyOn(_converse, 'emit'); spyOn(_converse, 'emit');
test_utils.openChatBoxFor(_converse, sender_jid) await test_utils.openChatBoxFor(_converse, sender_jid);
.then(() => { const view = _converse.chatboxviews.get(sender_jid);
view = _converse.chatboxviews.get(sender_jid);
expect(view.el.querySelectorAll('.chat-event').length).toBe(0); expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
// Insert <composing> message, to also check that // Insert <composing> message, to also check that
// text messages are inserted correctly with // text messages are inserted correctly with
// temporary chat events in the chat contents. // temporary chat events in the chat contents.
const msg = $msg({ let msg = $msg({
'to': _converse.bare_jid, 'to': _converse.bare_jid,
'xmlns': 'jabber:client', 'xmlns': 'jabber:client',
'from': sender_jid, 'from': sender_jid,
...@@ -1045,22 +1042,19 @@ ...@@ -1045,22 +1042,19 @@
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up() .c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
.tree(); .tree();
_converse.chatboxes.onMessage(msg); _converse.chatboxes.onMessage(msg);
return test_utils.waitUntil(() => view.model.messages.length); await test_utils.waitUntil(() => view.model.messages.length);
}).then(() => {
expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1); expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1);
const msg = $msg({ msg = $msg({
from: sender_jid, from: sender_jid,
to: _converse.connection.jid, to: _converse.connection.jid,
type: 'chat', type: 'chat',
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree(); }).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.chatboxes.onMessage(msg); _converse.chatboxes.onMessage(msg);
return test_utils.waitUntil(() => (view.model.messages.length > 1)); await test_utils.waitUntil(() => (view.model.messages.length > 1));
}).then(() => {
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object)); expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
expect($(view.el).find('.chat-state-notification').length).toBe(0); expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(0);
done(); done();
});
})); }));
}); });
......
...@@ -3739,7 +3739,7 @@ ...@@ -3739,7 +3739,7 @@
it("contains a link to a modal which can list groupchats publically available on the server", it("contains a link to a modal which can list groupchats publically available on the server",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { async function (done, _converse) {
var sendIQ = _converse.connection.sendIQ; var sendIQ = _converse.connection.sendIQ;
var sent_stanza, IQ_id; var sent_stanza, IQ_id;
...@@ -3753,8 +3753,7 @@ ...@@ -3753,8 +3753,7 @@
roomspanel.el.querySelector('.show-list-muc-modal').click(); roomspanel.el.querySelector('.show-list-muc-modal').click();
test_utils.closeControlBox(_converse); test_utils.closeControlBox(_converse);
const modal = roomspanel.list_rooms_modal; const modal = roomspanel.list_rooms_modal;
test_utils.waitUntil(() => u.isVisible(modal.el), 1000) await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
.then(() => {
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve()); spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
...@@ -3763,15 +3762,14 @@ ...@@ -3763,15 +3762,14 @@
const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit'; const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit';
modal.el.querySelector('input[type="submit"]').click(); modal.el.querySelector('input[type="submit"]').click();
return test_utils.waitUntil(() => _converse.chatboxes.length); await test_utils.waitUntil(() => _converse.chatboxes.length);
}).then(() => {
expect(sent_stanza.toLocaleString()).toBe( expect(sent_stanza.toLocaleString()).toBe(
`<iq from="dummy@localhost/resource" id="${IQ_id}" to="chat.shakespear.lit" type="get" xmlns="jabber:client">`+ `<iq from="dummy@localhost/resource" id="${IQ_id}" to="chat.shakespear.lit" type="get" xmlns="jabber:client">`+
`<query xmlns="http://jabber.org/protocol/disco#items"/>`+ `<query xmlns="http://jabber.org/protocol/disco#items"/>`+
`</iq>` `</iq>`
); );
var iq = $iq({ const iq = $iq({
from:'muc.localhost', from:'muc.localhost',
to:'dummy@localhost/pda', to:'dummy@localhost/pda',
id: IQ_id, id: IQ_id,
...@@ -3783,7 +3781,7 @@ ...@@ -3783,7 +3781,7 @@
.c('item', { jid:'inverness@chat.shakespeare.lit', name:'Macbeth&apos;s Castle'}).nodeTree; .c('item', { jid:'inverness@chat.shakespeare.lit', name:'Macbeth&apos;s Castle'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(iq)); _converse.connection._dataRecv(test_utils.createRequest(iq));
expect(modal.el.querySelectorAll('.available-chatrooms li').length).toBe(5); await test_utils.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 5);
const rooms = modal.el.querySelectorAll('.available-chatrooms li'); const rooms = modal.el.querySelectorAll('.available-chatrooms li');
expect(rooms[0].textContent.trim()).toBe("Groupchats found:"); expect(rooms[0].textContent.trim()).toBe("Groupchats found:");
...@@ -3793,13 +3791,11 @@ ...@@ -3793,13 +3791,11 @@
expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle"); expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle");
rooms[4].querySelector('.open-room').click(); rooms[4].querySelector('.open-room').click();
return test_utils.waitUntil(() => _converse.chatboxes.length > 1); await test_utils.waitUntil(() => _converse.chatboxes.length > 1);
}).then(() => {
expect(sizzle('.chatroom', _converse.el).filter(u.isVisible).length).toBe(1); // There should now be an open chatroom expect(sizzle('.chatroom', _converse.el).filter(u.isVisible).length).toBe(1); // There should now be an open chatroom
var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit'); var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit');
expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle"); expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle");
done(); done();
}).catch(_.partial(console.error, _));
})); }));
it("shows the number of unread mentions received", it("shows the number of unread mentions received",
......
...@@ -157,14 +157,14 @@ ...@@ -157,14 +157,14 @@
it("checks whether returned MAM messages from a MUC room are from the right JID", it("checks whether returned MAM messages from a MUC room are from the right JID",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
...@@ -217,7 +217,7 @@ ...@@ -217,7 +217,7 @@
* </set> * </set>
* </iq> * </iq>
*/ */
var stanza = $iq({'type': 'result', 'id': IQ_id}) const stanza = $iq({'type': 'result', 'id': IQ_id})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'}) .c('fin', {'xmlns': 'urn:xmpp:mam:2'})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'}) .c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('first', {'index': '0'}).t('23452-4534-1').up() .c('first', {'index': '0'}).t('23452-4534-1').up()
...@@ -225,11 +225,11 @@ ...@@ -225,11 +225,11 @@
.c('count').t('16'); .c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => callback.calls.count());
expect(callback).toHaveBeenCalled(); expect(callback).toHaveBeenCalled();
var args = callback.calls.argsFor(0); var args = callback.calls.argsFor(0);
expect(args[0].length).toBe(0); expect(args[0].length).toBe(0);
done(); done();
});
})); }));
it("can be used to query for all messages in a certain timespan", it("can be used to query for all messages in a certain timespan",
...@@ -279,9 +279,9 @@ ...@@ -279,9 +279,9 @@
it("throws a TypeError if an invalid date is provided", it("throws a TypeError if an invalid date is provided",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
...@@ -289,7 +289,6 @@ ...@@ -289,7 +289,6 @@
new TypeError('archive.query: invalid date provided for: start') new TypeError('archive.query: invalid date provided for: start')
); );
done(); done();
});
})); }));
it("can be used to query for all messages after a certain time", it("can be used to query for all messages after a certain time",
...@@ -500,22 +499,22 @@ ...@@ -500,22 +499,22 @@
it("accepts a callback function, which it passes the messages and a Strophe.RSM object", it("accepts a callback function, which it passes the messages and a Strophe.RSM object",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
var callback = jasmine.createSpy('callback'); const callback = jasmine.createSpy('callback');
_converse.api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback); _converse.api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback);
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid'); const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
/* <message id='aeb213' to='juliet@capulet.lit/chamber'> /* <message id='aeb213' to='juliet@capulet.lit/chamber'>
* <result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'> * <result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
...@@ -566,7 +565,7 @@ ...@@ -566,7 +565,7 @@
* </set> * </set>
* </iq> * </iq>
*/ */
var stanza = $iq({'type': 'result', 'id': IQ_id}) const stanza = $iq({'type': 'result', 'id': IQ_id})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'}) .c('fin', {'xmlns': 'urn:xmpp:mam:2'})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'}) .c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('first', {'index': '0'}).t('23452-4534-1').up() .c('first', {'index': '0'}).t('23452-4534-1').up()
...@@ -574,6 +573,7 @@ ...@@ -574,6 +573,7 @@
.c('count').t('16'); .c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => callback.calls.count());
expect(callback).toHaveBeenCalled(); expect(callback).toHaveBeenCalled();
var args = callback.calls.argsFor(0); var args = callback.calls.argsFor(0);
expect(args[0].length).toBe(2); expect(args[0].length).toBe(2);
...@@ -585,7 +585,6 @@ ...@@ -585,7 +585,6 @@
expect(args[1].first).toBe('23452-4534-1'); expect(args[1].first).toBe('23452-4534-1');
expect(args[1].last).toBe('09af3-cc343-b409f'); expect(args[1].last).toBe('09af3-cc343-b409f');
done() done()
});
})); }));
}); });
...@@ -594,11 +593,11 @@ ...@@ -594,11 +593,11 @@
it("is set once server support for MAM has been confirmed", it("is set once server support for MAM has been confirmed",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
...@@ -628,12 +627,13 @@ ...@@ -628,12 +627,13 @@
* </prefs> * </prefs>
* </iq> * </iq>
*/ */
var stanza = $iq({'type': 'result', 'id': IQ_id}) let stanza = $iq({'type': 'result', 'id': IQ_id})
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'roster'}) .c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'roster'})
.c('always').c('jid').t('romeo@montague.lit').up().up() .c('always').c('jid').t('romeo@montague.lit').up().up()
.c('never').c('jid').t('montague@montague.lit'); .c('never').c('jid').t('montague@montague.lit');
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => _converse.onMAMPreferences.calls.count());
expect(_converse.onMAMPreferences).toHaveBeenCalled(); expect(_converse.onMAMPreferences).toHaveBeenCalled();
expect(_converse.connection.sendIQ.calls.count()).toBe(2); expect(_converse.connection.sendIQ.calls.count()).toBe(2);
...@@ -661,12 +661,12 @@ ...@@ -661,12 +661,12 @@
stanza = $iq({'type': 'result', 'id': IQ_id}) stanza = $iq({'type': 'result', 'id': IQ_id})
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'always'}) .c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'always'})
.c('always').up() .c('always').up()
.c('never').up(); .c('never');
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => feature.save.calls.count());
expect(feature.save).toHaveBeenCalled(); expect(feature.save).toHaveBeenCalled();
expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation
done(); done();
});
})); }));
}); });
}); });
......
...@@ -52,27 +52,23 @@ ...@@ -52,27 +52,23 @@
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], null, ['rosterGroupsFetched'],
{ roster_groups: false }, { roster_groups: false },
function (done, _converse) { async function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza, modal; var contact, sent_stanza, IQ_id, stanza, modal;
test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp']) await test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp']);
.then(function () { await test_utils.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'), 300);
return test_utils.waitUntil(function () {
return _converse.xmppstatus.vcard.get('fullname');
}, 300);
}).then(function () {
/* The process by which a user subscribes to a contact, including /* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states. * the interaction between roster items and subscription states.
*/ */
test_utils.openControlBox(_converse); test_utils.openControlBox(_converse);
var cbview = _converse.chatboxviews.get('controlbox'); const cbview = _converse.chatboxviews.get('controlbox');
spyOn(_converse.roster, "addAndSubscribe").and.callThrough(); spyOn(_converse.roster, "addAndSubscribe").and.callThrough();
spyOn(_converse.roster, "addContactToRoster").and.callThrough(); spyOn(_converse.roster, "addContactToRoster").and.callThrough();
spyOn(_converse.roster, "sendContactAddIQ").and.callThrough(); spyOn(_converse.roster, "sendContactAddIQ").and.callThrough();
spyOn(_converse.api.vcard, "get").and.callThrough(); spyOn(_converse.api.vcard, "get").and.callThrough();
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
...@@ -80,15 +76,12 @@ ...@@ -80,15 +76,12 @@
cbview.el.querySelector('.add-contact').click() cbview.el.querySelector('.add-contact').click()
modal = _converse.rosterview.add_contact_modal; modal = _converse.rosterview.add_contact_modal;
return test_utils.waitUntil(function () { await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
return u.isVisible(modal.el);
}, 1000);
}).then(function () {
spyOn(modal, "addContactFromForm").and.callThrough(); spyOn(modal, "addContactFromForm").and.callThrough();
modal.delegateEvents(); modal.delegateEvents();
// Fill in the form and submit // Fill in the form and submit
var form = modal.el.querySelector('form.add-xmpp-contact'); const form = modal.el.querySelector('form.add-xmpp-contact');
form.querySelector('input').value = 'contact@example.org'; form.querySelector('input').value = 'contact@example.org';
form.querySelector('[type="submit"]').click(); form.querySelector('[type="submit"]').click();
...@@ -145,8 +138,8 @@ ...@@ -145,8 +138,8 @@
* </query> * </query>
* </iq> * </iq>
*/ */
var create = _converse.roster.create; const create = _converse.roster.create;
var sent_stanzas = []; const sent_stanzas = [];
spyOn(_converse.connection, 'send').and.callFake(function (stanza) { spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
sent_stanza = stanza; sent_stanza = stanza;
sent_stanzas.push(stanza.toLocaleString()); sent_stanzas.push(stanza.toLocaleString());
...@@ -162,12 +155,13 @@ ...@@ -162,12 +155,13 @@
'subscription': 'none', 'subscription': 'none',
'name': 'contact@example.org'}); 'name': 'contact@example.org'});
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
/* /* <iq type='result' id='set1'/>
* <iq type='result' id='set1'/>
*/ */
stanza = $iq({'type': 'result', 'id':IQ_id}); stanza = $iq({'type': 'result', 'id':IQ_id});
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => _converse.roster.create.calls.count());
// A contact should now have been created // A contact should now have been created
expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy(); expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
expect(contact.get('jid')).toBe('contact@example.org'); expect(contact.get('jid')).toBe('contact@example.org');
...@@ -179,10 +173,7 @@ ...@@ -179,10 +173,7 @@
* *
* <presence to='contact@example.org' type='subscribe'/> * <presence to='contact@example.org' type='subscribe'/>
*/ */
return test_utils.waitUntil(function () { await test_utils.waitUntil(() => sent_stanzas.filter(s => s.match('presence')));
return sent_stanzas.length == 1;
}, 300);
}).then(function () {
expect(contact.subscribe).toHaveBeenCalled(); expect(contact.subscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec) expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
`<presence to="contact@example.org" type="subscribe" xmlns="jabber:client">`+ `<presence to="contact@example.org" type="subscribe" xmlns="jabber:client">`+
...@@ -220,12 +211,12 @@ ...@@ -220,12 +211,12 @@
expect(_converse.roster.updateContact).toHaveBeenCalled(); expect(_converse.roster.updateContact).toHaveBeenCalled();
// Check that the user is now properly shown as a pending // Check that the user is now properly shown as a pending
// contact in the roster. // contact in the roster.
return test_utils.waitUntil(function () { await test_utils.waitUntil(function () {
var $header = $('a:contains("Pending contacts")'); var $header = $('a:contains("Pending contacts")');
var $contacts = $header.parent().find('li:visible'); var $contacts = $header.parent().find('li:visible');
return $contacts.length; return $contacts.length;
}, 600); }, 600);
}).then(function () {
var $header = $('a:contains("Pending contacts")'); var $header = $('a:contains("Pending contacts")');
var $contacts = $header.parent().find('li'); var $contacts = $header.parent().find('li');
expect($contacts.length).toBe(1); expect($contacts.length).toBe(1);
...@@ -289,16 +280,15 @@ ...@@ -289,16 +280,15 @@
// The contact should now be visible as an existing // The contact should now be visible as an existing
// contact (but still offline). // contact (but still offline).
return test_utils.waitUntil(function () { await test_utils.waitUntil(function () {
var $header = $('a:contains("My contacts")'); var $header = $('a:contains("My contacts")');
var $contacts = $header.parent().find('li:visible'); var $contacts = $header.parent().find('li:visible');
return $contacts.length; return $contacts.length;
}, 600); }, 600);
}).then(function () { $header = $('a:contains("My contacts")');
var $header = $('a:contains("My contacts")');
expect($header.length).toBe(1); expect($header.length).toBe(1);
expect($header.is(":visible")).toBeTruthy(); expect($header.is(":visible")).toBeTruthy();
var $contacts = $header.parent().find('li'); $contacts = $header.parent().find('li');
expect($contacts.length).toBe(1); expect($contacts.length).toBe(1);
// Check that it has the right classes and text // Check that it has the right classes and text
expect($contacts.hasClass('to')).toBeTruthy(); expect($contacts.hasClass('to')).toBeTruthy();
...@@ -372,7 +362,7 @@ ...@@ -372,7 +362,7 @@
expect($contacts.hasClass('to')).toBeFalsy(); expect($contacts.hasClass('to')).toBeFalsy();
expect($contacts.hasClass('both')).toBeTruthy(); expect($contacts.hasClass('both')).toBeTruthy();
done(); done();
});
})); }));
it("Alternate Flow: Contact Declines Subscription Request", it("Alternate Flow: Contact Declines Subscription Request",
...@@ -466,7 +456,7 @@ ...@@ -466,7 +456,7 @@
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], null, ['rosterGroupsFetched'],
{ roster_groups: false }, { roster_groups: false },
function (done, _converse) { async function (done, _converse) {
var sent_IQ, IQ_id, jid = 'annegreet.gomez@localhost'; var sent_IQ, IQ_id, jid = 'annegreet.gomez@localhost';
test_utils.openControlBox(_converse); test_utils.openControlBox(_converse);
...@@ -480,13 +470,9 @@ ...@@ -480,13 +470,9 @@
sent_IQ = iq; sent_IQ = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
return test_utils.waitUntil(function () { const $header = $('a:contains("My contacts")');
var $header = $('a:contains("My contacts")'); await test_utils.waitUntil(() => $header.parent().find('li').length);
var $contacts = $header.parent().find('li');
return $contacts.length;
}, 600).then(function () {
var $header = $('a:contains("My contacts")');
// remove the first user // remove the first user
$header.parent().find('li .remove-xmpp-contact').get(0).click(); $header.parent().find('li .remove-xmpp-contact').get(0).click();
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
...@@ -519,12 +505,11 @@ ...@@ -519,12 +505,11 @@
// Receive confirmation from the contact's server // Receive confirmation from the contact's server
// <iq type='result' id='remove1'/> // <iq type='result' id='remove1'/>
var stanza = $iq({'type': 'result', 'id':IQ_id}); const stanza = $iq({'type': 'result', 'id':IQ_id});
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
// Our contact has now been removed // Our contact has now been removed
expect(typeof _converse.roster.get(jid) === "undefined").toBeTruthy(); await test_utils.waitUntil(() => typeof _converse.roster.get(jid) === "undefined");
done(); done();
});
})); }));
it("Receiving a subscription request", mock.initConverseWithPromises( it("Receiving a subscription request", mock.initConverseWithPromises(
......
(function (root, factory) { (function (root, factory) {
define(["jquery", "jasmine", "mock", "test-utils"], factory); define(["jquery", "jasmine", "mock", "test-utils"], factory);
} (this, function ($, jasmine, mock, test_utils) { } (this, function ($, jasmine, mock, test_utils) {
var _ = converse.env._; const $iq = converse.env.$iq;
var Strophe = converse.env.Strophe; const $msg = converse.env.$msg;
var $pres = converse.env.$pres; const $pres = converse.env.$pres;
var $msg = converse.env.$msg; const Strophe = converse.env.Strophe;
var $iq = converse.env.$iq; const _ = converse.env._;
var u = converse.env.utils; const sizzle = converse.env.sizzle;
const u = converse.env.utils;
var checkHeaderToggling = function (group) {
const checkHeaderToggling = function (group) {
var $group = $(group); var $group = $(group);
var toggle = group.querySelector('a.group-toggle'); var toggle = group.querySelector('a.group-toggle');
expect(u.isVisible($group[0])).toBeTruthy(); expect(u.isVisible($group[0])).toBeTruthy();
...@@ -38,12 +40,12 @@ ...@@ -38,12 +40,12 @@
it("supports roster versioning", it("supports roster versioning",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
test_utils.waitUntil( let node = await test_utils.waitUntil(
() => _.filter(IQ_stanzas, iq => iq.nodeTree.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop() () => _.filter(IQ_stanzas, iq => iq.nodeTree.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop()
).then(node => { );
let stanza = node.nodeTree; let stanza = node.nodeTree;
expect(_converse.roster.data.get('version')).toBeUndefined(); expect(_converse.roster.data.get('version')).toBeUndefined();
expect(node.toLocaleString()).toBe( expect(node.toLocaleString()).toBe(
...@@ -60,6 +62,8 @@ ...@@ -60,6 +62,8 @@
}).c('item', {'jid': 'nurse@example.com'}).up() }).c('item', {'jid': 'nurse@example.com'}).up()
.c('item', {'jid': 'romeo@example.com'}) .c('item', {'jid': 'romeo@example.com'})
_converse.connection._dataRecv(test_utils.createRequest(result)); _converse.connection._dataRecv(test_utils.createRequest(result));
await test_utils.waitUntil(() => _converse.roster.models.length > 1);
expect(_converse.roster.data.get('version')).toBe('ver7'); expect(_converse.roster.data.get('version')).toBe('ver7');
expect(_converse.roster.models.length).toBe(2); expect(_converse.roster.models.length).toBe(2);
...@@ -88,7 +92,6 @@ ...@@ -88,7 +92,6 @@
expect(_converse.roster.models.length).toBe(1); expect(_converse.roster.models.length).toBe(1);
expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com'); expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com');
done(); done();
});
})); }));
describe("The live filter", function () { describe("The live filter", function () {
...@@ -549,17 +552,15 @@ ...@@ -549,17 +552,15 @@
it("can be collapsed under their own header", it("can be collapsed under their own header",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
_addContacts(_converse); _addContacts(_converse);
test_utils.waitUntil(function () { await test_utils.waitUntil(() => $(_converse.rosterview.el).find('.roster-group:visible li').length, 1000);
return $(_converse.rosterview.el).find('.roster-group:visible li').length; await checkHeaderToggling.apply(
}, 500).then(function () {
checkHeaderToggling.apply(
_converse, _converse,
[_converse.rosterview.get('Pending contacts').el] [_converse.rosterview.get('Pending contacts').el]
).then(done); );
}); done();
})); }));
it("can be added to the roster", it("can be added to the roster",
...@@ -662,10 +663,10 @@ ...@@ -662,10 +663,10 @@
it("do not have a header if there aren't any", it("do not have a header if there aren't any",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.openControlBox(); test_utils.openControlBox();
var name = mock.pend_names[0]; const name = mock.pend_names[0];
_converse.roster.create({ _converse.roster.create({
jid: name.replace(/ /g,'.').toLowerCase() + '@localhost', jid: name.replace(/ /g,'.').toLowerCase() + '@localhost',
subscription: 'none', subscription: 'none',
...@@ -676,17 +677,18 @@ ...@@ -676,17 +677,18 @@
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) {
if (typeof callback === "function") { return callback(); } if (typeof callback === "function") { return callback(); }
}); });
test_utils.waitUntil(function () { await test_utils.waitUntil(function () {
var $pending_contacts = $(_converse.rosterview.get('Pending contacts').el); var $pending_contacts = $(_converse.rosterview.get('Pending contacts').el);
return $pending_contacts.is(':visible') && $pending_contacts.find('li:visible').length; return $pending_contacts.is(':visible') && $pending_contacts.find('li:visible').length;
}, 700).then(function () { }, 700)
$(_converse.rosterview.el).find(".pending-contact-name:contains('"+name+"')") $(_converse.rosterview.el).find(".pending-contact-name:contains('"+name+"')")
.parent().siblings('.remove-xmpp-contact')[0].click(); .parent().siblings('.remove-xmpp-contact')[0].click();
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
expect(_converse.connection.sendIQ).toHaveBeenCalled(); expect(_converse.connection.sendIQ).toHaveBeenCalled();
expect(u.isVisible(_converse.rosterview.get('Pending contacts').el)).toEqual(false);
await test_utils.waitUntil(() => !u.isVisible(_converse.rosterview.get('Pending contacts').el));
done(); done();
});
})); }));
it("is shown when a new private message is received", it("is shown when a new private message is received",
...@@ -822,20 +824,18 @@ ...@@ -822,20 +824,18 @@
it("can be removed by the user", it("can be removed by the user",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
var sent_IQ;
_addContacts(_converse); _addContacts(_converse);
test_utils.waitUntil(function () { await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('li').length);
return $(_converse.rosterview.el).find('li').length; const name = mock.cur_names[0];
}, 500).then(function () { const jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
var name = mock.cur_names[0]; const contact = _converse.roster.get(jid);
var jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
var contact = _converse.roster.get(jid);
spyOn(window, 'confirm').and.returnValue(true); spyOn(window, 'confirm').and.returnValue(true);
spyOn(contact, 'removeFromRoster').and.callThrough(); spyOn(contact, 'removeFromRoster').and.callThrough();
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
let sent_IQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_IQ = iq; sent_IQ = iq;
callback(); callback();
...@@ -849,15 +849,14 @@ ...@@ -849,15 +849,14 @@
`<query xmlns="jabber:iq:roster"><item jid="max.frankfurter@localhost" subscription="remove"/></query>`+ `<query xmlns="jabber:iq:roster"><item jid="max.frankfurter@localhost" subscription="remove"/></query>`+
`</iq>`); `</iq>`);
expect(contact.removeFromRoster).toHaveBeenCalled(); expect(contact.removeFromRoster).toHaveBeenCalled();
expect($(_converse.rosterview.el).find(".open-chat:contains('"+name+"')").length).toEqual(0); await test_utils.waitUntil(() => $(_converse.rosterview.el).find(".open-chat:contains('"+name+"')").length === 0);
done(); done();
});
})); }));
it("do not have a header if there aren't any", it("do not have a header if there aren't any",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.openControlBox(); test_utils.openControlBox();
var name = mock.cur_names[0]; var name = mock.cur_names[0];
...@@ -868,24 +867,20 @@ ...@@ -868,24 +867,20 @@
ask: null, ask: null,
fullname: name fullname: name
}); });
test_utils.waitUntil(function () { await test_utils.waitUntil(() => $(_converse.rosterview.el).find('.roster-group:visible li').length, 1000);
return $(_converse.rosterview.el).find('.roster-group:visible li').length;
}, 700).then(function () {
spyOn(window, 'confirm').and.returnValue(true); spyOn(window, 'confirm').and.returnValue(true);
spyOn(contact, 'removeFromRoster').and.callThrough(); spyOn(contact, 'removeFromRoster').and.callThrough();
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) {
if (typeof callback === "function") { return callback(); } if (typeof callback === "function") { return callback(); }
}); });
expect($(_converse.rosterview.el).find('.roster-group').css('display')).toEqual('block'); expect($(_converse.rosterview.el).find('.roster-group').css('display')).toEqual('block');
$(_converse.rosterview.el).find(".open-chat:contains('"+name+"')") $(_converse.rosterview.el).find(".open-chat:contains('"+name+"')")
.parent().find('.remove-xmpp-contact')[0].click(); .parent().find('.remove-xmpp-contact')[0].click();
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
expect(_converse.connection.sendIQ).toHaveBeenCalled(); expect(_converse.connection.sendIQ).toHaveBeenCalled();
expect(contact.removeFromRoster).toHaveBeenCalled(); expect(contact.removeFromRoster).toHaveBeenCalled();
expect($(_converse.rosterview.el).find('.roster-group').length).toEqual(0); await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length === 0);
done(); done();
});
})); }));
it("can change their status to online and be sorted alphabetically", it("can change their status to online and be sorted alphabetically",
......
...@@ -533,6 +533,9 @@ converse.plugins.add('converse-chatview', { ...@@ -533,6 +533,9 @@ converse.plugins.add('converse-chatview', {
prev_msg_date = _.isNull(prev_msg_el) ? null : prev_msg_el.getAttribute('data-isodate'), prev_msg_date = _.isNull(prev_msg_el) ? null : prev_msg_el.getAttribute('data-isodate'),
next_msg_date = next_msg_el.getAttribute('data-isodate'); next_msg_date = next_msg_el.getAttribute('data-isodate');
if (_.isNull(prev_msg_date) && _.isNull(next_msg_date)) {
return;
}
if (_.isNull(prev_msg_date) || moment(next_msg_date).isAfter(prev_msg_date, 'day')) { if (_.isNull(prev_msg_date) || moment(next_msg_date).isAfter(prev_msg_date, 'day')) {
const day_date = moment(next_msg_date).startOf('day'); const day_date = moment(next_msg_date).startOf('day');
next_msg_el.insertAdjacentHTML('beforeBegin', next_msg_el.insertAdjacentHTML('beforeBegin',
...@@ -722,8 +725,15 @@ converse.plugins.add('converse-chatview', { ...@@ -722,8 +725,15 @@ converse.plugins.add('converse-chatview', {
*/ */
const view = new _converse.MessageView({'model': message}); const view = new _converse.MessageView({'model': message});
await view.render(); await view.render();
this.clearChatStateNotification(message); this.clearChatStateNotification(message);
if (!view.el.innerHTML) {
// An "inactive" CSN message (for example) will have an
// empty body. No need to then continue.
return _converse.log(
"Not inserting a message with empty element",
Strophe.LogLevel.INFO
);
}
this.insertMessage(view); this.insertMessage(view);
this.insertDayIndicator(view.el); this.insertDayIndicator(view.el);
this.setScrollPosition(view.el); this.setScrollPosition(view.el);
......
...@@ -60,6 +60,10 @@ converse.plugins.add('converse-message-view', { ...@@ -60,6 +60,10 @@ converse.plugins.add('converse-message-view', {
if (this.model.isOnlyChatStateNotification()) { if (this.model.isOnlyChatStateNotification()) {
this.renderChatStateNotification() this.renderChatStateNotification()
} else if (this.model.get('file') && !this.model.get('oob_url')) { } else if (this.model.get('file') && !this.model.get('oob_url')) {
if (!this.model.file) {
_converse.log("Attempted to render a file upload message with no file data");
return this.el;
}
this.renderFileUploadProgresBar(); this.renderFileUploadProgresBar();
} else if (this.model.get('type') === 'error') { } else if (this.model.get('type') === 'error') {
this.renderErrorMessage(); this.renderErrorMessage();
...@@ -204,7 +208,7 @@ converse.plugins.add('converse-message-view', { ...@@ -204,7 +208,7 @@ converse.plugins.add('converse-message-view', {
renderFileUploadProgresBar () { renderFileUploadProgresBar () {
const msg = u.stringToElement(tpl_file_progress( const msg = u.stringToElement(tpl_file_progress(
_.extend(this.model.toJSON(), { _.extend(this.model.toJSON(), {
'filesize': filesize(this.model.get('file').size), 'filesize': filesize(this.model.file.size),
}))); })));
this.replaceElement(msg); this.replaceElement(msg);
this.renderAvatar(); this.renderAvatar();
......
...@@ -367,16 +367,14 @@ converse.plugins.add('converse-muc-views', { ...@@ -367,16 +367,14 @@ converse.plugins.add('converse-muc-views', {
updateRoomsList () { updateRoomsList () {
/* Send an IQ stanza to the server asking for all groupchats /* Send an IQ stanza to the server asking for all groupchats
*/ */
_converse.connection.sendIQ( const iq = $iq({
$iq({
'to': this.model.get('muc_domain'), 'to': this.model.get('muc_domain'),
'from': _converse.connection.jid, 'from': _converse.connection.jid,
'type': "get" 'type': "get"
}).c("query", {xmlns: Strophe.NS.DISCO_ITEMS}), }).c("query", {xmlns: Strophe.NS.DISCO_ITEMS});
this.onRoomsFound.bind(this), _converse.api.sendIQ(iq)
this.informNoRoomsFound.bind(this), .then(iq => this.onRoomsFound(iq))
5000 .catch(iq => this.informNoRoomsFound())
);
}, },
showRooms (ev) { showRooms (ev) {
...@@ -805,7 +803,7 @@ converse.plugins.add('converse-muc-views', { ...@@ -805,7 +803,7 @@ converse.plugins.add('converse-muc-views', {
const item = $build("item", {nick, role}); const item = $build("item", {nick, role});
const iq = $iq({to: groupchat, type: "set"}).c("query", {xmlns: Strophe.NS.MUC_ADMIN}).cnode(item.node); const iq = $iq({to: groupchat, type: "set"}).c("query", {xmlns: Strophe.NS.MUC_ADMIN}).cnode(item.node);
if (reason !== null) { iq.c("reason", reason); } if (reason !== null) { iq.c("reason", reason); }
return _converse.connection.sendIQ(iq, onSuccess, onError); return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
}, },
verifyRoles (roles) { verifyRoles (roles) {
......
...@@ -68,10 +68,6 @@ converse.plugins.add('converse-chatboxes', { ...@@ -68,10 +68,6 @@ converse.plugins.add('converse-chatboxes', {
this.setVCard(); this.setVCard();
if (this.get('file')) { if (this.get('file')) {
this.on('change:put', this.uploadFile, this); this.on('change:put', this.uploadFile, this);
if (!_.includes([_converse.SUCCESS, _converse.FAILURE], this.get('upload'))) {
this.getRequestSlotURL();
}
} }
if (this.isOnlyChatStateNotification()) { if (this.isOnlyChatStateNotification()) {
window.setTimeout(this.destroy.bind(this), 20000); window.setTimeout(this.destroy.bind(this), 20000);
...@@ -132,20 +128,20 @@ converse.plugins.add('converse-chatboxes', { ...@@ -132,20 +128,20 @@ converse.plugins.add('converse-chatboxes', {
* *
* https://xmpp.org/extensions/xep-0363.html#request * https://xmpp.org/extensions/xep-0363.html#request
*/ */
const file = this.get('file'); if (_.isNil(this.file)) {
return new Promise((resolve, reject) => { return Promise.reject(new Error("file is undefined"));
}
const iq = converse.env.$iq({ const iq = converse.env.$iq({
'from': _converse.jid, 'from': _converse.jid,
'to': this.get('slot_request_url'), 'to': this.get('slot_request_url'),
'type': 'get' 'type': 'get'
}).c('request', { }).c('request', {
'xmlns': Strophe.NS.HTTPUPLOAD, 'xmlns': Strophe.NS.HTTPUPLOAD,
'filename': file.name, 'filename': this.file.name,
'size': file.size, 'size': this.file.size,
'content-type': file.type 'content-type': this.file.type
}) })
_converse.connection.sendIQ(iq, resolve, reject); return _converse.api.sendIQ(iq);
});
}, },
async getRequestSlotURL () { async getRequestSlotURL () {
...@@ -420,8 +416,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -420,8 +416,8 @@ converse.plugins.add('converse-chatboxes', {
async sendFiles (files) { async sendFiles (files) {
const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain); const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain),
const item = result.pop(), item = result.pop(),
data = item.dataforms.where({'FORM_TYPE': {'value': Strophe.NS.HTTPUPLOAD, 'type': "hidden"}}).pop(), data = item.dataforms.where({'FORM_TYPE': {'value': Strophe.NS.HTTPUPLOAD, 'type': "hidden"}}).pop(),
max_file_size = window.parseInt(_.get(data, 'attributes.max-file-size.value')), max_file_size = window.parseInt(_.get(data, 'attributes.max-file-size.value')),
slot_request_url = _.get(item, 'id'); slot_request_url = _.get(item, 'id');
...@@ -429,7 +425,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -429,7 +425,7 @@ converse.plugins.add('converse-chatboxes', {
if (!slot_request_url) { if (!slot_request_url) {
this.messages.create({ this.messages.create({
'message': __("Sorry, looks like file upload is not supported by your server."), 'message': __("Sorry, looks like file upload is not supported by your server."),
'type': 'error', 'type': 'error'
}); });
return; return;
} }
...@@ -438,17 +434,20 @@ converse.plugins.add('converse-chatboxes', { ...@@ -438,17 +434,20 @@ converse.plugins.add('converse-chatboxes', {
return this.messages.create({ return this.messages.create({
'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.', 'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.',
file.name, filesize(max_file_size)), file.name, filesize(max_file_size)),
'type': 'error', 'type': 'error'
}); });
} else { } else {
this.messages.create( const message = this.messages.create(
_.extend( _.extend(
this.getOutgoingMessageAttributes(), { this.getOutgoingMessageAttributes(), {
'file': file, 'file': file,
'progress': 0, 'progress': 0,
'slot_request_url': slot_request_url 'slot_request_url': slot_request_url
}) }), {'silent': true}
); );
message.file = file;
this.messages.trigger('add', message);
message.getRequestSlotURL();
} }
}); });
}, },
......
...@@ -1641,6 +1641,7 @@ _converse.api = { ...@@ -1641,6 +1641,7 @@ _converse.api = {
*/ */
'send' (stanza) { 'send' (stanza) {
_converse.connection.send(stanza); _converse.connection.send(stanza);
_converse.emit('send', stanza);
}, },
/** /**
...@@ -1650,9 +1651,10 @@ _converse.api = { ...@@ -1650,9 +1651,10 @@ _converse.api = {
* @returns {Promise} A promise which resolves when we receive a `result` stanza * @returns {Promise} A promise which resolves when we receive a `result` stanza
* or is rejected when we receive an `error` stanza. * or is rejected when we receive an `error` stanza.
*/ */
'sendIQ' (stanza) { 'sendIQ' (stanza, timeout) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT); _converse.connection.sendIQ(stanza, resolve, reject, timeout || _converse.IQ_TIMEOUT);
_converse.emit('send', stanza);
}); });
} }
}; };
......
...@@ -99,9 +99,8 @@ function queryForArchivedMessages (_converse, options, callback, errback) { ...@@ -99,9 +99,8 @@ function queryForArchivedMessages (_converse, options, callback, errback) {
return true; return true;
}, Strophe.NS.MAM); }, Strophe.NS.MAM);
_converse.connection.sendIQ( _converse.api.sendIQ(stanza, _converse.message_archiving_timeout)
stanza, .then(iq => {
function (iq) {
_converse.connection.deleteHandler(message_handler); _converse.connection.deleteHandler(message_handler);
if (_.isFunction(callback)) { if (_.isFunction(callback)) {
const set = iq.querySelector('set'); const set = iq.querySelector('set');
...@@ -112,13 +111,13 @@ function queryForArchivedMessages (_converse, options, callback, errback) { ...@@ -112,13 +111,13 @@ function queryForArchivedMessages (_converse, options, callback, errback) {
} }
callback(messages, rsm); callback(messages, rsm);
} }
}, }).catch(e => {
function () {
_converse.connection.deleteHandler(message_handler); _converse.connection.deleteHandler(message_handler);
if (_.isFunction(errback)) { errback.apply(this, arguments); } if (_.isFunction(errback)) {
}, errback.apply(this, arguments);
_converse.message_archiving_timeout }
); return;
});
} }
...@@ -333,7 +332,7 @@ converse.plugins.add('converse-mam', { ...@@ -333,7 +332,7 @@ converse.plugins.add('converse-mam', {
message_archiving_timeout: 8000, // Time (in milliseconds) to wait before aborting MAM request message_archiving_timeout: 8000, // Time (in milliseconds) to wait before aborting MAM request
}); });
_converse.onMAMError = function (model, iq) { _converse.onMAMError = function (iq) {
if (iq.querySelectorAll('feature-not-implemented').length) { if (iq.querySelectorAll('feature-not-implemented').length) {
_converse.log( _converse.log(
"Message Archive Management (XEP-0313) not supported by this server", "Message Archive Management (XEP-0313) not supported by this server",
...@@ -365,17 +364,14 @@ converse.plugins.add('converse-mam', { ...@@ -365,17 +364,14 @@ converse.plugins.add('converse-mam', {
'xmlns':Strophe.NS.MAM, 'xmlns':Strophe.NS.MAM,
'default':_converse.message_archiving 'default':_converse.message_archiving
}); });
_.each(preference.children, function (child) { _.each(preference.children, child => stanza.cnode(child).up());
stanza.cnode(child).up();
});
_converse.connection.sendIQ(stanza, _.partial(function (feature, iq) {
// XXX: Strictly speaking, the server should respond with the updated prefs // XXX: Strictly speaking, the server should respond with the updated prefs
// (see example 18: https://xmpp.org/extensions/xep-0313.html#config) // (see example 18: https://xmpp.org/extensions/xep-0313.html#config)
// but Prosody doesn't do this, so we don't rely on it. // but Prosody doesn't do this, so we don't rely on it.
feature.save({'preferences': {'default':_converse.message_archiving}}); _converse.api.sendIQ(stanza)
}, feature), .then(() => feature.save({'preferences': {'default':_converse.message_archiving}}))
_converse.onMAMError .catch(_converse.onMAMError);
);
} else { } else {
feature.save({'preferences': {'default':_converse.message_archiving}}); feature.save({'preferences': {'default':_converse.message_archiving}});
} }
...@@ -388,11 +384,9 @@ converse.plugins.add('converse-mam', { ...@@ -388,11 +384,9 @@ converse.plugins.add('converse-mam', {
prefs['default'] !== _converse.message_archiving && // eslint-disable-line dot-notation prefs['default'] !== _converse.message_archiving && // eslint-disable-line dot-notation
!_.isUndefined(_converse.message_archiving) ) { !_.isUndefined(_converse.message_archiving) ) {
// Ask the server for archiving preferences // Ask the server for archiving preferences
_converse.connection.sendIQ( _converse.api.sendIQ($iq({'type': 'get'}).c('prefs', {'xmlns': Strophe.NS.MAM}))
$iq({'type': 'get'}).c('prefs', {'xmlns': Strophe.NS.MAM}), .then(_.partial(_converse.onMAMPreferences, feature))
_.partial(_converse.onMAMPreferences, feature), .catch(_converse.onMAMError);
_.partial(_converse.onMAMError, feature)
);
} }
}); });
......
...@@ -618,16 +618,10 @@ converse.plugins.add('converse-muc', { ...@@ -618,16 +618,10 @@ converse.plugins.add('converse-muc', {
* Returns a promise which resolves once the response IQ * Returns a promise which resolves once the response IQ
* has been received. * has been received.
*/ */
return new Promise((resolve, reject) => { return _converse.api.sendIQ(
_converse.connection.sendIQ( $iq({'to': this.get('jid'), 'type': "get"})
$iq({ .c("query", {xmlns: Strophe.NS.MUC_OWNER})
'to': this.get('jid'),
'type': "get"
}).c("query", {xmlns: Strophe.NS.MUC_OWNER}),
resolve,
reject
); );
});
}, },
sendConfiguration (config, callback, errback) { sendConfiguration (config, callback, errback) {
...@@ -650,7 +644,7 @@ converse.plugins.add('converse-muc', { ...@@ -650,7 +644,7 @@ converse.plugins.add('converse-muc', {
_.each(config || [], function (node) { iq.cnode(node).up(); }); _.each(config || [], function (node) { iq.cnode(node).up(); });
callback = _.isUndefined(callback) ? _.noop : _.partial(callback, iq.nodeTree); callback = _.isUndefined(callback) ? _.noop : _.partial(callback, iq.nodeTree);
errback = _.isUndefined(errback) ? _.noop : _.partial(errback, iq.nodeTree); errback = _.isUndefined(errback) ? _.noop : _.partial(errback, iq.nodeTree);
return _converse.connection.sendIQ(iq, callback, errback); return _converse.api.sendIQ(iq).then(callback).catch(errback);
}, },
saveAffiliationAndRole (pres) { saveAffiliationAndRole (pres) {
...@@ -683,7 +677,6 @@ converse.plugins.add('converse-muc', { ...@@ -683,7 +677,6 @@ converse.plugins.add('converse-muc', {
* (Object) member: Map containing the member's jid and * (Object) member: Map containing the member's jid and
* optionally a reason and affiliation. * optionally a reason and affiliation.
*/ */
return new Promise((resolve, reject) => {
const iq = $iq({to: this.get('jid'), type: "set"}) const iq = $iq({to: this.get('jid'), type: "set"})
.c("query", {xmlns: Strophe.NS.MUC_ADMIN}) .c("query", {xmlns: Strophe.NS.MUC_ADMIN})
.c("item", { .c("item", {
...@@ -694,8 +687,7 @@ converse.plugins.add('converse-muc', { ...@@ -694,8 +687,7 @@ converse.plugins.add('converse-muc', {
if (!_.isUndefined(member.reason)) { if (!_.isUndefined(member.reason)) {
iq.c("reason", member.reason); iq.c("reason", member.reason);
} }
_converse.connection.sendIQ(iq, resolve, reject); return _converse.api.sendIQ(iq);
});
}, },
setAffiliations (members) { setAffiliations (members) {
......
...@@ -329,7 +329,7 @@ converse.plugins.add('converse-roster', { ...@@ -329,7 +329,7 @@ converse.plugins.add('converse-roster', {
const iq = $iq({type: 'set'}) const iq = $iq({type: 'set'})
.c('query', {xmlns: Strophe.NS.ROSTER}) .c('query', {xmlns: Strophe.NS.ROSTER})
.c('item', {jid: this.get('jid'), subscription: "remove"}); .c('item', {jid: this.get('jid'), subscription: "remove"});
_converse.connection.sendIQ(iq, callback, errback); _converse.api.sendIQ(iq).then(callback).catch(errback);
return this; return this;
} }
}); });
...@@ -451,7 +451,7 @@ converse.plugins.add('converse-roster', { ...@@ -451,7 +451,7 @@ converse.plugins.add('converse-roster', {
this.addContactToRoster(jid, name, groups, attributes).then(handler, handler); this.addContactToRoster(jid, name, groups, attributes).then(handler, handler);
}, },
sendContactAddIQ (jid, name, groups, callback, errback) { sendContactAddIQ (jid, name, groups) {
/* Send an IQ stanza to the XMPP server to add a new roster contact. /* Send an IQ stanza to the XMPP server to add a new roster contact.
* *
* Parameters: * Parameters:
...@@ -462,14 +462,14 @@ converse.plugins.add('converse-roster', { ...@@ -462,14 +462,14 @@ converse.plugins.add('converse-roster', {
* (Function) errback - A function to call if an error occurred * (Function) errback - A function to call if an error occurred
*/ */
name = _.isEmpty(name)? jid: name; name = _.isEmpty(name)? jid: name;
const iq = $iq({type: 'set'}) const iq = $iq({'type': 'set'})
.c('query', {xmlns: Strophe.NS.ROSTER}) .c('query', {'xmlns': Strophe.NS.ROSTER})
.c('item', { jid, name }); .c('item', { jid, name });
_.each(groups, function (group) { iq.c('group').t(group).up(); }); _.each(groups, group => iq.c('group').t(group).up());
_converse.connection.sendIQ(iq, callback, errback); _converse.api.sendIQ(iq);
}, },
addContactToRoster (jid, name, groups, attributes) { async addContactToRoster (jid, name, groups, attributes) {
/* Adds a RosterContact instance to _converse.roster and /* Adds a RosterContact instance to _converse.roster and
* registers the contact on the XMPP server. * registers the contact on the XMPP server.
* Returns a promise which is resolved once the XMPP server has * Returns a promise which is resolved once the XMPP server has
...@@ -481,27 +481,22 @@ converse.plugins.add('converse-roster', { ...@@ -481,27 +481,22 @@ converse.plugins.add('converse-roster', {
* (Array of Strings) groups - Any roster groups the user might belong to * (Array of Strings) groups - Any roster groups the user might belong to
* (Object) attributes - Any additional attributes to be stored on the user's model. * (Object) attributes - Any additional attributes to be stored on the user's model.
*/ */
return new Promise((resolve, reject) => {
groups = groups || []; groups = groups || [];
this.sendContactAddIQ(jid, name, groups, try {
() => { await this.sendContactAddIQ(jid, name, groups);
const contact = this.create(_.assignIn({ } catch (e) {
_converse.log(e, Strophe.LogLevel.ERROR);
alert(__('Sorry, there was an error while trying to add %1$s as a contact.', name));
return e;
}
return this.create(_.assignIn({
'ask': undefined, 'ask': undefined,
'nickname': name, 'nickname': name,
groups, groups,
jid, jid,
'requesting': false, 'requesting': false,
'subscription': 'none' 'subscription': 'none'
}, attributes), {sort: false}); }, attributes), {'sort': false});
resolve(contact);
},
function (err) {
alert(__('Sorry, there was an error while trying to add %1$s as a contact.', name));
_converse.log(err, Strophe.LogLevel.ERROR);
resolve(err);
}
);
});
}, },
subscribeBack (bare_jid, presence) { subscribeBack (bare_jid, presence) {
...@@ -570,24 +565,26 @@ converse.plugins.add('converse-roster', { ...@@ -570,24 +565,26 @@ converse.plugins.add('converse-roster', {
return _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver') && this.data.get('version'); return _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver') && this.data.get('version');
}, },
fetchFromServer () { async fetchFromServer () {
/* Fetch the roster from the XMPP server */ /* Fetch the roster from the XMPP server */
return new Promise((resolve, reject) => { const stanza = $iq({
const iq = $iq({
'type': 'get', 'type': 'get',
'id': _converse.connection.getUniqueId('roster') 'id': _converse.connection.getUniqueId('roster')
}).c('query', {xmlns: Strophe.NS.ROSTER}); }).c('query', {xmlns: Strophe.NS.ROSTER});
if (this.rosterVersioningSupported()) { if (this.rosterVersioningSupported()) {
iq.attrs({'ver': this.data.get('version')}); stanza.attrs({'ver': this.data.get('version')});
} }
const callback = _.flow(this.onReceivedFromServer.bind(this), resolve); let iq;
const errback = function (iq) { try {
const errmsg = "Error while trying to fetch roster from the server"; iq = await _converse.api.sendIQ(stanza);
_converse.log(errmsg, Strophe.LogLevel.ERROR); } catch (e) {
reject(new Error(errmsg)); _converse.log(e, Strophe.LogLevel.ERROR);
return _converse.log(
"Error while trying to fetch roster from the server",
Strophe.LogLevel.ERROR
);
} }
return _converse.connection.sendIQ(iq, callback, errback); return this.onReceivedFromServer(iq);
});
}, },
onReceivedFromServer (iq) { onReceivedFromServer (iq) {
......
...@@ -56,7 +56,7 @@ converse.plugins.add('converse-vcard', { ...@@ -56,7 +56,7 @@ converse.plugins.add('converse-vcard', {
}); });
function onVCardData (jid, iq, callback) { async function onVCardData (jid, iq) {
const vcard = iq.querySelector('vCard'); const vcard = iq.querySelector('vCard');
let result = {}; let result = {};
if (!_.isNull(vcard)) { if (!_.isNull(vcard)) {
...@@ -75,24 +75,10 @@ converse.plugins.add('converse-vcard', { ...@@ -75,24 +75,10 @@ converse.plugins.add('converse-vcard', {
} }
if (result.image) { if (result.image) {
const buffer = u.base64ToArrayBuffer(result['image']); const buffer = u.base64ToArrayBuffer(result['image']);
crypto.subtle.digest('SHA-1', buffer) const ab = await crypto.subtle.digest('SHA-1', buffer);
.then(ab => {
result['image_hash'] = u.arrayBufferToHex(ab); result['image_hash'] = u.arrayBufferToHex(ab);
if (callback) callback(result);
});
} else {
if (callback) callback(result);
}
}
function onVCardError (jid, iq, errback) {
if (errback) {
errback({
'stanza': iq,
'jid': jid,
'vcard_error': moment().format()
});
} }
return result;
} }
function createStanza (type, jid, vcard_el) { function createStanza (type, jid, vcard_el) {
...@@ -113,7 +99,7 @@ converse.plugins.add('converse-vcard', { ...@@ -113,7 +99,7 @@ converse.plugins.add('converse-vcard', {
return _converse.api.sendIQ(createStanza("set", jid, vcard_el)); return _converse.api.sendIQ(createStanza("set", jid, vcard_el));
} }
function getVCard (_converse, jid) { async function getVCard (_converse, jid) {
/* Request the VCard of another user. Returns a promise. /* Request the VCard of another user. Returns a promise.
* *
* Parameters: * Parameters:
...@@ -121,14 +107,17 @@ converse.plugins.add('converse-vcard', { ...@@ -121,14 +107,17 @@ converse.plugins.add('converse-vcard', {
* is being requested. * is being requested.
*/ */
const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid; const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
return new Promise((resolve, reject) => { let iq;
_converse.connection.sendIQ( try {
createStanza("get", to), iq = await _converse.api.sendIQ(createStanza("get", to))
_.partial(onVCardData, jid, _, resolve), } catch (iq) {
_.partial(onVCardError, jid, _, resolve), return {
_converse.IQ_TIMEOUT 'stanza': iq,
); 'jid': jid,
}); 'vcard_error': moment().format()
}
}
return onVCardData(jid, iq);
} }
/* Event handlers */ /* Event handlers */
......
{
"name": "@converse/headless",
"version": "4.0.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"backbone.browserStorage": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/backbone.browserStorage/-/backbone.browserStorage-0.0.4.tgz",
"integrity": "sha512-4LvDP2IkOu9Nt6kj6ft4moKmqKqm3c0WY3c/aie0Cf374wjFuO7vCh/afcKdu1YSuVsryM8yH90/J7yqWbaPHw==",
"requires": {
"backbone": "~1.x.x",
"underscore": ">=1.4.0"
},
"dependencies": {
"backbone": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz",
"integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=",
"requires": {
"underscore": ">=1.8.3"
}
},
"underscore": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
"integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg=="
}
}
}
}
}
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
"gitHead": "9641dcdc820e029b05930479c242d2b707bbe8e2", "gitHead": "9641dcdc820e029b05930479c242d2b707bbe8e2",
"dependencies": { "dependencies": {
"backbone": "1.3.3", "backbone": "1.3.3",
"backbone.browserStorage": "0.0.4", "backbone.browserStorage": "jcbrand/Backbone.browserStorage#03bfa13f68b71f97be361840adc5a5064f57b47e",
"es6-promise": "^4.1.0", "es6-promise": "^4.1.0",
"filesize": "^3.6.1", "filesize": "^3.6.1",
"lodash": "^4.17.10", "lodash": "^4.17.10",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment