Only initialize bookmarks and show icon if PEP is supported

which we check by checking if the PEP identity is provided.
https://xmpp.org/extensions/xep-0163.html#support
This commit is contained in:
JC Brand 2018-02-07 17:30:44 +01:00
parent bbe47b465d
commit 5f3761dc7f
10 changed files with 671 additions and 583 deletions

View File

@ -12,6 +12,7 @@
} (this, function (jasmine, $, converse, utils, mock, test_utils) { } (this, function (jasmine, $, converse, utils, mock, test_utils) {
"use strict"; "use strict";
var $iq = converse.env.$iq, var $iq = converse.env.$iq,
Backbone = converse.env.Backbone,
Strophe = converse.env.Strophe, Strophe = converse.env.Strophe,
_ = converse.env._, _ = converse.env._,
u = converse.env.utils; u = converse.env.utils;
@ -20,7 +21,7 @@
it("can be bookmarked", mock.initConverseWithPromises( it("can be bookmarked", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, function (done, _converse) { null, ['rosterGroupsFetched'], {}, function (done, _converse) {
var sent_stanza, IQ_id; var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; var sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -30,105 +31,110 @@
spyOn(_converse.connection, 'getUniqueId').and.callThrough(); spyOn(_converse.connection, 'getUniqueId').and.callThrough();
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC'); test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
var jid = 'theplay@conference.shakespeare.lit'; var jid = 'theplay@conference.shakespeare.lit';
var view = _converse.chatboxviews.get(jid); var view = _converse.chatboxviews.get(jid);
spyOn(view, 'renderBookmarkForm').and.callThrough(); spyOn(view, 'renderBookmarkForm').and.callThrough();
spyOn(view, 'closeForm').and.callThrough(); spyOn(view, 'closeForm').and.callThrough();
var $bookmark = $(view.el).find('.icon-pushpin'); test_utils.waitUntil(function () {
$bookmark[0].click(); return !_.isNull(view.el.querySelector('.toggle-bookmark'));
expect(view.renderBookmarkForm).toHaveBeenCalled(); }, 300).then(function () {
var $bookmark = $(view.el).find('.icon-pushpin');
$bookmark[0].click();
expect(view.renderBookmarkForm).toHaveBeenCalled();
view.el.querySelector('.button-cancel').click(); view.el.querySelector('.button-cancel').click();
expect(view.closeForm).toHaveBeenCalled(); expect(view.closeForm).toHaveBeenCalled();
expect($bookmark.hasClass('on-button'), false); expect($bookmark.hasClass('on-button'), false);
$bookmark[0].click(); $bookmark[0].click();
expect(view.renderBookmarkForm).toHaveBeenCalled(); expect(view.renderBookmarkForm).toHaveBeenCalled();
/* Client uploads data: /* Client uploads data:
* -------------------- * --------------------
* <iq from='juliet@capulet.lit/balcony' type='set' id='pip1'> * <iq from='juliet@capulet.lit/balcony' type='set' id='pip1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'> * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <publish node='storage:bookmarks'> * <publish node='storage:bookmarks'>
* <item id='current'> * <item id='current'>
* <storage xmlns='storage:bookmarks'> * <storage xmlns='storage:bookmarks'>
* <conference name='The Play&apos;s the Thing' * <conference name='The Play&apos;s the Thing'
* autojoin='true' * autojoin='true'
* jid='theplay@conference.shakespeare.lit'> * jid='theplay@conference.shakespeare.lit'>
* <nick>JC</nick> * <nick>JC</nick>
* </conference> * </conference>
* </storage> * </storage>
* </item> * </item>
* </publish> * </publish>
* <publish-options> * <publish-options>
* <x xmlns='jabber:x:data' type='submit'> * <x xmlns='jabber:x:data' type='submit'>
* <field var='FORM_TYPE' type='hidden'> * <field var='FORM_TYPE' type='hidden'>
* <value>http://jabber.org/protocol/pubsub#publish-options</value> * <value>http://jabber.org/protocol/pubsub#publish-options</value>
* </field> * </field>
* <field var='pubsub#persist_items'> * <field var='pubsub#persist_items'>
* <value>true</value> * <value>true</value>
* </field> * </field>
* <field var='pubsub#access_model'> * <field var='pubsub#access_model'>
* <value>whitelist</value> * <value>whitelist</value>
* </field> * </field>
* </x> * </x>
* </publish-options> * </publish-options>
* </pubsub> * </pubsub>
* </iq> * </iq>
*/ */
expect(view.model.get('bookmarked')).toBeFalsy(); expect(view.model.get('bookmarked')).toBeFalsy();
var $form = $(view.el).find('.chatroom-form'); var $form = $(view.el).find('.chatroom-form');
$form.find('input[name="name"]').val('Play&apos;s the Thing'); $form.find('input[name="name"]').val('Play&apos;s the Thing');
$form.find('input[name="autojoin"]').prop('checked', true); $form.find('input[name="autojoin"]').prop('checked', true);
$form.find('input[name="nick"]').val('JC'); $form.find('input[name="nick"]').val('JC');
view.el.querySelector('.button-primary').click(); view.el.querySelector('.button-primary').click();
expect(view.model.get('bookmarked')).toBeTruthy(); expect(view.model.get('bookmarked')).toBeTruthy();
expect($bookmark.hasClass('on-button'), true); expect($bookmark.hasClass('on-button'), true);
expect(sent_stanza.toLocaleString()).toBe( expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+ "<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+ "<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<publish node='storage:bookmarks'>"+ "<publish node='storage:bookmarks'>"+
"<item id='current'>"+ "<item id='current'>"+
"<storage xmlns='storage:bookmarks'>"+ "<storage xmlns='storage:bookmarks'>"+
"<conference name='Play&amp;apos;s the Thing' autojoin='true' jid='theplay@conference.shakespeare.lit'>"+ "<conference name='Play&amp;apos;s the Thing' autojoin='true' jid='theplay@conference.shakespeare.lit'>"+
"<nick>JC</nick>"+ "<nick>JC</nick>"+
"</conference>"+ "</conference>"+
"</storage>"+ "</storage>"+
"</item>"+ "</item>"+
"</publish>"+ "</publish>"+
"<publish-options>"+ "<publish-options>"+
"<x xmlns='jabber:x:data' type='submit'>"+ "<x xmlns='jabber:x:data' type='submit'>"+
"<field var='FORM_TYPE' type='hidden'>"+ "<field var='FORM_TYPE' type='hidden'>"+
"<value>http://jabber.org/protocol/pubsub#publish-options</value>"+ "<value>http://jabber.org/protocol/pubsub#publish-options</value>"+
"</field>"+ "</field>"+
"<field var='pubsub#persist_items'>"+ "<field var='pubsub#persist_items'>"+
"<value>true</value>"+ "<value>true</value>"+
"</field>"+ "</field>"+
"<field var='pubsub#access_model'>"+ "<field var='pubsub#access_model'>"+
"<value>whitelist</value>"+ "<value>whitelist</value>"+
"</field>"+ "</field>"+
"</x>"+ "</x>"+
"</publish-options>"+ "</publish-options>"+
"</pubsub>"+ "</pubsub>"+
"</iq>" "</iq>"
); );
/* Server acknowledges successful storage /* Server acknowledges successful storage
* *
* <iq to='juliet@capulet.lit/balcony' type='result' id='pip1'/> * <iq to='juliet@capulet.lit/balcony' type='result' id='pip1'/>
*/ */
var stanza = $iq({ var stanza = $iq({
'to':_converse.connection.jid, 'to':_converse.connection.jid,
'type':'result', 'type':'result',
'id':IQ_id 'id':IQ_id
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
// We ignore this IQ stanza... (unless it's an error stanza), so
// nothing to test for here.
done();
}); });
_converse.connection._dataRecv(test_utils.createRequest(stanza));
// We ignore this IQ stanza... (unless it's an error stanza), so
// nothing to test for here.
done();
})); }));
it("will be automatically opened if 'autojoin' is set on the bookmark", mock.initConverseWithPromises( it("will be automatically opened if 'autojoin' is set on the bookmark", mock.initConverseWithPromises(
@ -161,13 +167,18 @@
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
var view = _converse.chatboxviews.get('lounge@localhost'); var view = _converse.chatboxviews.get('lounge@localhost');
var $bookmark_icon = $(view.el.querySelector('.icon-pushpin'));
expect($bookmark_icon.hasClass('button-on')).toBeFalsy(); test_utils.waitUntil(function () {
view.model.set('bookmarked', true); return !_.isNull(view.el.querySelector('.toggle-bookmark'));
expect($bookmark_icon.hasClass('button-on')).toBeTruthy(); }, 300).then(function () {
view.model.set('bookmarked', false); var bookmark_icon = view.el.querySelector('.icon-pushpin');
expect($bookmark_icon.hasClass('button-on')).toBeFalsy(); expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
done(); view.model.set('bookmarked', true);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeTruthy();
view.model.set('bookmarked', false);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
done();
});
})); }));
it("can be unbookmarked", mock.initConverseWithPromises( it("can be unbookmarked", mock.initConverseWithPromises(
@ -175,61 +186,68 @@
var sent_stanza, IQ_id; var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; var sendIQ = _converse.connection.sendIQ;
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC'); test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
var jid = 'theplay@conference.shakespeare.lit'; var jid = 'theplay@conference.shakespeare.lit';
var view = _converse.chatboxviews.get(jid); var view = _converse.chatboxviews.get(jid);
spyOn(view, 'toggleBookmark').and.callThrough();
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
view.delegateEvents();
_converse.bookmarks.create({
'jid': view.model.get('jid'),
'autojoin': false,
'name': 'The Play',
'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1);
expect(view.model.get('bookmarked')).toBeTruthy();
var $bookmark_icon = $(view.el.querySelector('.icon-pushpin'));
expect($bookmark_icon.hasClass('button-on')).toBeTruthy();
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { test_utils.waitUntil(function () {
sent_stanza = iq; return !_.isNull(view.el.querySelector('.toggle-bookmark'));
IQ_id = sendIQ.bind(this)(iq, callback, errback); }, 300).then(function () {
}); spyOn(view, 'toggleBookmark').and.callThrough();
spyOn(_converse.connection, 'getUniqueId').and.callThrough(); spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
$bookmark_icon[0].click(); view.delegateEvents();
expect(view.toggleBookmark).toHaveBeenCalled();
expect($bookmark_icon.hasClass('button-on')).toBeFalsy();
expect(_converse.bookmarks.length).toBe(0);
// Check that an IQ stanza is sent out, containing no _converse.bookmarks.create({
// conferences to bookmark (since we removed the one and 'jid': view.model.get('jid'),
// only bookmark). 'autojoin': false,
expect(sent_stanza.toLocaleString()).toBe( 'name': 'The Play',
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+ 'nick': ' Othello'
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+ });
"<publish node='storage:bookmarks'>"+ expect(_converse.bookmarks.length).toBe(1);
"<item id='current'>"+ expect(view.model.get('bookmarked')).toBeTruthy();
"<storage xmlns='storage:bookmarks'/>"+ var $bookmark_icon = $(view.el.querySelector('.icon-pushpin'));
"</item>"+ expect($bookmark_icon.hasClass('button-on')).toBeTruthy();
"</publish>"+
"<publish-options>"+ spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
"<x xmlns='jabber:x:data' type='submit'>"+ sent_stanza = iq;
"<field var='FORM_TYPE' type='hidden'>"+ IQ_id = sendIQ.bind(this)(iq, callback, errback);
"<value>http://jabber.org/protocol/pubsub#publish-options</value>"+ });
"</field>"+ spyOn(_converse.connection, 'getUniqueId').and.callThrough();
"<field var='pubsub#persist_items'>"+ $bookmark_icon[0].click();
"<value>true</value>"+ expect(view.toggleBookmark).toHaveBeenCalled();
"</field>"+ expect($bookmark_icon.hasClass('button-on')).toBeFalsy();
"<field var='pubsub#access_model'>"+ expect(_converse.bookmarks.length).toBe(0);
"<value>whitelist</value>"+
"</field>"+ // Check that an IQ stanza is sent out, containing no
"</x>"+ // conferences to bookmark (since we removed the one and
"</publish-options>"+ // only bookmark).
"</pubsub>"+ expect(sent_stanza.toLocaleString()).toBe(
"</iq>" "<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
); "<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
done(); "<publish node='storage:bookmarks'>"+
"<item id='current'>"+
"<storage xmlns='storage:bookmarks'/>"+
"</item>"+
"</publish>"+
"<publish-options>"+
"<x xmlns='jabber:x:data' type='submit'>"+
"<field var='FORM_TYPE' type='hidden'>"+
"<value>http://jabber.org/protocol/pubsub#publish-options</value>"+
"</field>"+
"<field var='pubsub#persist_items'>"+
"<value>true</value>"+
"</field>"+
"<field var='pubsub#access_model'>"+
"<value>whitelist</value>"+
"</field>"+
"</x>"+
"</publish-options>"+
"</pubsub>"+
"</iq>"
);
done();
});
})); }));
}); });
@ -308,88 +326,21 @@
})); }));
it("can be retrieved from the XMPP server", mock.initConverseWithPromises( it("can be retrieved from the XMPP server", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {}, function (done, _converse) { ['send'], ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
function (done, _converse) {
/* Client requests all items test_utils.waitUntil(function () {
* ------------------------- return _converse.bookmarks;
* }, 300).then(function () {
* <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'> /* Client requests all items
* <pubsub xmlns='http://jabber.org/protocol/pubsub'> * -------------------------
* <items node='storage:bookmarks'/> *
* </pubsub> * <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
* </iq> * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
*/ * <items node='storage:bookmarks'/>
var IQ_id; * </pubsub>
expect(_.filter(_converse.connection.send.calls.all(), function (call) { * </iq>
var stanza = call.args[0]; */
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
return;
}
// XXX: Wrapping in a div is a workaround for PhantomJS
var div = document.createElement('div');
div.appendChild(stanza);
if (div.innerHTML ===
'<iq from="dummy@localhost/resource" type="get" '+
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"></items>'+
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
}
}).length).toBe(1);
/*
* Server returns all items
* ------------------------
* <iq type='result'
* to='juliet@capulet.lit/randomID'
* id='retrieve1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <items node='storage:bookmarks'>
* <item id='current'>
* <storage xmlns='storage:bookmarks'>
* <conference name='The Play&apos;s the Thing'
* autojoin='true'
* jid='theplay@conference.shakespeare.lit'>
* <nick>JC</nick>
* </conference>
* </storage>
* </item>
* </items>
* </pubsub>
* </iq>
*/
expect(_converse.bookmarks.models.length).toBe(0);
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'})
.c('conference', {
'name': 'The Play&apos;s the Thing',
'autojoin': 'true',
'jid': 'theplay@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Another room',
'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit'
}).c('nick').t('JC').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(_converse.bookmarks.models.length).toBe(2);
expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
done();
}));
describe("The rooms panel", function () {
it("shows a list of bookmarks", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {}, function (done, _converse) {
test_utils.openControlBox().openRoomsPanel(_converse);
var IQ_id; var IQ_id;
expect(_.filter(_converse.connection.send.calls.all(), function (call) { expect(_.filter(_converse.connection.send.calls.all(), function (call) {
var stanza = call.args[0]; var stanza = call.args[0];
@ -411,6 +362,28 @@
} }
}).length).toBe(1); }).length).toBe(1);
/*
* Server returns all items
* ------------------------
* <iq type='result'
* to='juliet@capulet.lit/randomID'
* id='retrieve1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <items node='storage:bookmarks'>
* <item id='current'>
* <storage xmlns='storage:bookmarks'>
* <conference name='The Play&apos;s the Thing'
* autojoin='true'
* jid='theplay@conference.shakespeare.lit'>
* <nick>JC</nick>
* </conference>
* </storage>
* </item>
* </items>
* </pubsub>
* </iq>
*/
expect(_converse.bookmarks.models.length).toBe(0);
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id}) var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB}) .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'}) .c('items', {'node': 'storage:bookmarks'})
@ -418,97 +391,156 @@
.c('storage', {'xmlns': 'storage:bookmarks'}) .c('storage', {'xmlns': 'storage:bookmarks'})
.c('conference', { .c('conference', {
'name': 'The Play&apos;s the Thing', 'name': 'The Play&apos;s the Thing',
'autojoin': 'false', 'autojoin': 'true',
'jid': 'theplay@conference.shakespeare.lit' 'jid': 'theplay@conference.shakespeare.lit'
}).c('nick').t('JC').up().up() }).c('nick').t('JC').up().up()
.c('conference', {
'name': '1st Bookmark',
'autojoin': 'false',
'jid': 'first@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Bookmark with a very very long name that will be shortened',
'autojoin': 'false',
'jid': 'longname@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', { .c('conference', {
'name': 'Another room', 'name': 'Another room',
'autojoin': 'false', 'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit' 'jid': 'another@conference.shakespeare.lit'
}).c('nick').t('JC').up().up(); }).c('nick').t('JC').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(_converse.bookmarks.models.length).toBe(2);
expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
done();
});
}));
describe("The rooms panel", function () {
it("shows a list of bookmarks", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {}, function (done, _converse) {
test_utils.waitUntil(function () { test_utils.waitUntil(function () {
return $('#chatrooms dl.bookmarks dd').length; return _converse.bookmarks;
}, 300).then(function () { }, 300).then(function () {
expect($('#chatrooms dl.bookmarks dd').length).toBe(4);
expect($('#chatrooms dl.bookmarks dd a').text().trim()).toBe(
"1st Bookmark  Another room  Bookmark with a very very long name that will be shortened  The Play&apos;s the Thing")
spyOn(window, 'confirm').and.returnValue(true); test_utils.openControlBox().openRoomsPanel(_converse);
$('#chatrooms dl.bookmarks dd:nth-child(2) a:nth-child(2)')[0].click(); var IQ_id;
expect(window.confirm).toHaveBeenCalled(); expect(_.filter(_converse.connection.send.calls.all(), function (call) {
var stanza = call.args[0];
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
return;
}
// XXX: Wrapping in a div is a workaround for PhantomJS
var div = document.createElement('div');
div.appendChild(stanza);
if (div.innerHTML ===
'<iq from="dummy@localhost/resource" type="get" '+
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"></items>'+
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
}
}).length).toBe(1);
return test_utils.waitUntil(function () { var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
return $('#chatrooms dl.bookmarks dd a').text().trim() === .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
"1st Bookmark  Bookmark with a very very long name that will be shortened  The Play&apos;s the Thing"; .c('items', {'node': 'storage:bookmarks'})
}, 300) .c('item', {'id': 'current'})
}).then(done); .c('storage', {'xmlns': 'storage:bookmarks'})
.c('conference', {
'name': 'The Play&apos;s the Thing',
'autojoin': 'false',
'jid': 'theplay@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': '1st Bookmark',
'autojoin': 'false',
'jid': 'first@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Bookmark with a very very long name that will be shortened',
'autojoin': 'false',
'jid': 'longname@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Another room',
'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit'
}).c('nick').t('JC').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
test_utils.waitUntil(function () {
return $('#chatrooms dl.bookmarks dd').length;
}, 300).then(function () {
expect($('#chatrooms dl.bookmarks dd').length).toBe(4);
expect($('#chatrooms dl.bookmarks dd a').text().trim()).toBe(
"1st Bookmark  Another room  Bookmark with a very very long name that will be shortened  The Play&apos;s the Thing")
spyOn(window, 'confirm').and.returnValue(true);
$('#chatrooms dl.bookmarks dd:nth-child(2) a:nth-child(2)')[0].click();
expect(window.confirm).toHaveBeenCalled();
return test_utils.waitUntil(function () {
return $('#chatrooms dl.bookmarks dd a').text().trim() ===
"1st Bookmark  Bookmark with a very very long name that will be shortened  The Play&apos;s the Thing";
}, 300)
}).then(done);
});
})); }));
it("remembers the toggle state of the bookmarks list", mock.initConverseWithPromises( it("remembers the toggle state of the bookmarks list", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {}, function (done, _converse) { ['send'], ['rosterGroupsFetched'], {}, function (done, _converse) {
var IQ_id;
expect(_.filter(_converse.connection.send.calls.all(), function (call) {
var stanza = call.args[0];
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
return;
}
// XXX: Wrapping in a div is a workaround for PhantomJS
var div = document.createElement('div');
div.appendChild(stanza);
if (div.innerHTML ===
'<iq from="dummy@localhost/resource" type="get" '+
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"></items>'+
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
}
}).length).toBe(1);
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.bookmarks.create({
'jid': 'theplay@conference.shakespeare.lit',
'autojoin': false,
'name': 'The Play',
'nick': ''
});
test_utils.openControlBox().openRoomsPanel(_converse);
test_utils.waitUntil(function () { test_utils.waitUntil(function () {
return $('#chatrooms dl.bookmarks dd:visible').length; return _converse.bookmarks;
}, 300).then(function () { }, 300).then(function () {
expect($('#chatrooms dl.bookmarks').hasClass('collapsed')).toBeFalsy(); var IQ_id;
expect($('#chatrooms dl.bookmarks dd:visible').length).toBe(1); expect(_.filter(_converse.connection.send.calls.all(), function (call) {
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED); var stanza = call.args[0];
$('#chatrooms .bookmarks-toggle')[0].click(); if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
expect($('#chatrooms dl.bookmarks').hasClass('collapsed')).toBeTruthy(); return;
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED); }
$('#chatrooms .bookmarks-toggle')[0].click(); // XXX: Wrapping in a div is a workaround for PhantomJS
expect($('#chatrooms dl.bookmarks').hasClass('collapsed')).toBeFalsy(); var div = document.createElement('div');
expect($('#chatrooms dl.bookmarks dd:visible').length).toBe(1); div.appendChild(stanza);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED); if (div.innerHTML ===
done(); '<iq from="dummy@localhost/resource" type="get" '+
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"></items>'+
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
}
}).length).toBe(1);
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.bookmarks.create({
'jid': 'theplay@conference.shakespeare.lit',
'autojoin': false,
'name': 'The Play',
'nick': ''
});
test_utils.openControlBox().openRoomsPanel(_converse);
test_utils.waitUntil(function () {
return $('#chatrooms dl.bookmarks dd:visible').length;
}, 300).then(function () {
expect($('#chatrooms dl.bookmarks').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms dl.bookmarks dd:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
$('#chatrooms .bookmarks-toggle')[0].click();
expect($('#chatrooms dl.bookmarks').hasClass('collapsed')).toBeTruthy();
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED);
$('#chatrooms .bookmarks-toggle')[0].click();
expect($('#chatrooms dl.bookmarks').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms dl.bookmarks dd:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
done();
});
}); });
})); }));
}); });
@ -521,36 +553,40 @@
{ hide_open_bookmarks: true }, { hide_open_bookmarks: true },
function (done, _converse) { function (done, _converse) {
test_utils.openControlBox().openRoomsPanel(_converse); test_utils.waitUntil(function () {
// XXX Create bookmarks view here, otherwise we need to mock stanza return _converse.bookmarks;
// traffic for it to get created. }, 300).then(function () {
_converse.bookmarksview = new _converse.BookmarksView( test_utils.openControlBox().openRoomsPanel(_converse);
{'model': _converse.bookmarks} // XXX Create bookmarks view here, otherwise we need to mock stanza
); // traffic for it to get created.
_converse.emit('bookmarksInitialized'); _converse.bookmarksview = new _converse.BookmarksView(
{'model': _converse.bookmarks}
);
_converse.emit('bookmarksInitialized');
// Check that it's there // Check that it's there
var jid = 'room@conference.example.org'; var jid = 'room@conference.example.org';
_converse.bookmarks.create({ _converse.bookmarks.create({
'jid': jid, 'jid': jid,
'autojoin': false, 'autojoin': false,
'name': 'The Play', 'name': 'The Play',
'nick': ' Othello' 'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1);
var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
// Check that it disappears once the room is opened
var bookmark = _converse.bookmarksview.el.querySelector(".open-room");
bookmark.click();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
// Check that it reappears once the room is closed
var view = _converse.chatboxviews.get(jid);
view.close();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy();
done();
}); });
expect(_converse.bookmarks.length).toBe(1);
var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
// Check that it disappears once the room is opened
var bookmark = _converse.bookmarksview.el.querySelector(".open-room");
bookmark.click();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
// Check that it reappears once the room is closed
var view = _converse.chatboxviews.get(jid);
view.close();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy();
done();
})); }));
}); });
})); }));

View File

@ -57,7 +57,7 @@
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { function (done, _converse) {
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp') test_utils.waitUntilFeatureSupportConfirmed(_converse, 'localhost', 'vcard-temp')
.then(function () { .then(function () {
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return _converse.xmppstatus.get('fullname'); return _converse.xmppstatus.get('fullname');
@ -1228,7 +1228,7 @@
function (done, _converse) { function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza; var contact, sent_stanza, IQ_id, stanza;
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp') test_utils.waitUntilFeatureSupportConfirmed(_converse, 'localhost', 'vcard-temp')
.then(function () { .then(function () {
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return _converse.xmppstatus.get('fullname'); return _converse.xmppstatus.get('fullname');
@ -1842,7 +1842,7 @@
function (done, _converse) { function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza; var contact, sent_stanza, IQ_id, stanza;
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp') test_utils.waitUntilFeatureSupportConfirmed(_converse, 'localhost', 'vcard-temp')
.then(function () { .then(function () {
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return _converse.xmppstatus.get('fullname'); return _converse.xmppstatus.get('fullname');
@ -1989,7 +1989,7 @@
function (done, _converse) { function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza; var contact, sent_stanza, IQ_id, stanza;
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp') test_utils.waitUntilFeatureSupportConfirmed(_converse, 'localhost', 'vcard-temp')
.then(function () { .then(function () {
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return _converse.xmppstatus.get('fullname'); return _converse.xmppstatus.get('fullname');

View File

@ -762,7 +762,6 @@
}); });
var view = _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); var view = _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
spyOn(view, 'generateHeadingHTML').and.callThrough();
var features_stanza = $iq({ var features_stanza = $iq({
from: 'coven@chat.shakespeare.lit', from: 'coven@chat.shakespeare.lit',
'id': IQ_id, 'id': IQ_id,
@ -791,10 +790,12 @@
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'}) .c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0); .c('value').t(0);
_converse.connection._dataRecv(test_utils.createRequest(features_stanza)); _converse.connection._dataRecv(test_utils.createRequest(features_stanza));
test_utils.waitUntil(function () {
expect(view.generateHeadingHTML).toHaveBeenCalled(); return _.get(view.el.querySelector('.chatroom-description'), 'textContent');
expect($(view.el.querySelector('.chatroom-description')).text()).toBe('This is the description'); }).then(function () {
done(); expect($(view.el.querySelector('.chatroom-description')).text()).toBe('This is the description');
done();
});
})); }));
it("will specially mark messages in which you are mentioned", it("will specially mark messages in which you are mentioned",
@ -825,8 +826,7 @@
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { function (done, _converse) {
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'localhost', 'vcard-temp')
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
.then(function () { .then(function () {
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return _converse.xmppstatus.get('fullname'); return _converse.xmppstatus.get('fullname');
@ -890,19 +890,24 @@
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
spyOn(view, 'saveAffiliationAndRole').and.callThrough();
// We pretend this is a new room, so no disco info is returned. test_utils.waitUntil(function () {
var features_stanza = $iq({ return !_.isNull(view.el.querySelector('.toggle-bookmark'));
from: 'coven@chat.shakespeare.lit', }, 300).then(function () {
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
/* <presence to="dummy@localhost/_converse.js-29092160" spyOn(view, 'saveAffiliationAndRole').and.callThrough();
// We pretend this is a new room, so no disco info is returned.
var features_stanza = $iq({
from: 'coven@chat.shakespeare.lit',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
/* <presence to="dummy@localhost/_converse.js-29092160"
* from="coven@chat.shakespeare.lit/some1"> * from="coven@chat.shakespeare.lit/some1">
* <x xmlns="http://jabber.org/protocol/muc#user"> * <x xmlns="http://jabber.org/protocol/muc#user">
* <item affiliation="owner" jid="dummy@localhost/_converse.js-29092160" role="moderator"/> * <item affiliation="owner" jid="dummy@localhost/_converse.js-29092160" role="moderator"/>
@ -910,191 +915,198 @@
* </x> * </x>
* </presence></body> * </presence></body>
*/ */
var presence = $pres({ var presence = $pres({
to: 'dummy@localhost/_converse.js-29092160', to: 'dummy@localhost/_converse.js-29092160',
from: 'coven@chat.shakespeare.lit/some1' from: 'coven@chat.shakespeare.lit/some1'
}).c('x', {xmlns: Strophe.NS.MUC_USER}) }).c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', { .c('item', {
'affiliation': 'owner', 'affiliation': 'owner',
'jid': 'dummy@localhost/_converse.js-29092160', 'jid': 'dummy@localhost/_converse.js-29092160',
'role': 'moderator' 'role': 'moderator'
}).up() }).up()
.c('status', {code: '110'}); .c('status', {code: '110'});
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.saveAffiliationAndRole).toHaveBeenCalled(); expect(view.saveAffiliationAndRole).toHaveBeenCalled();
expect($(view.el.querySelector('.configure-chatroom-button')).is(':visible')).toBeTruthy(); expect($(view.el.querySelector('.toggle-chatbox-button')).is(':visible')).toBeTruthy();
expect($(view.el.querySelector('.toggle-chatbox-button')).is(':visible')).toBeTruthy(); expect($(view.el.querySelector('.toggle-bookmark')).is(':visible')).toBeTruthy();
expect($(view.el.querySelector('.toggle-bookmark')).is(':visible')).toBeTruthy();
view.el.querySelector('.configure-chatroom-button').click();
/* Check that an IQ is sent out, asking for the test_utils.waitUntil(function () {
* configuration form. return !_.isNull(view.el.querySelector('.configure-chatroom-button'));
* See: // http://xmpp.org/extensions/xep-0045.html#example-163 }, 300).then(function () {
* expect($(view.el.querySelector('.configure-chatroom-button')).is(':visible')).toBeTruthy();
* <iq from='crone1@shakespeare.lit/desktop'
* id='config1'
* to='coven@chat.shakespeare.lit'
* type='get'>
* <query xmlns='http://jabber.org/protocol/muc#owner'/>
* </iq>
*/
expect(sent_IQ.toLocaleString()).toBe(
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='http://jabber.org/protocol/muc#owner'/>"+
"</iq>");
/* Server responds with the configuration form. view.el.querySelector('.configure-chatroom-button').click();
* See: // http://xmpp.org/extensions/xep-0045.html#example-165
*/
var config_stanza = $iq({from: 'coven@chat.shakespeare.lit',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'result'})
.c('query', { 'xmlns': 'http://jabber.org/protocol/muc#owner'})
.c('x', { 'xmlns': 'jabber:x:data', 'type': 'form'})
.c('title').t('Configuration for "coven" Room').up()
.c('instructions').t('Complete this form to modify the configuration of your room.').up()
.c('field', {'type': 'hidden', 'var': 'FORM_TYPE'})
.c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up()
.c('field', {
'label': 'Natural-Language Room Name',
'type': 'text-single',
'var': 'muc#roomconfig_roomname'})
.c('value').t('A Dark Cave').up().up()
.c('field', {
'label': 'Short Description of Room',
'type': 'text-single',
'var': 'muc#roomconfig_roomdesc'})
.c('value').t('The place for all good witches!').up().up()
.c('field', {
'label': 'Enable Public Logging?',
'type': 'boolean',
'var': 'muc#roomconfig_enablelogging'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Allow Occupants to Change Subject?',
'type': 'boolean',
'var': 'muc#roomconfig_changesubject'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Allow Occupants to Invite Others?',
'type': 'boolean',
'var': 'muc#roomconfig_allowinvites'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Who Can Send Private Messages?',
'type': 'list-single',
'var': 'muc#roomconfig_allowpm'})
.c('value').t('anyone').up()
.c('option', {'label': 'Anyone'})
.c('value').t('anyone').up().up()
.c('option', {'label': 'Anyone with Voice'})
.c('value').t('participants').up().up()
.c('option', {'label': 'Moderators Only'})
.c('value').t('moderators').up().up()
.c('option', {'label': 'Nobody'})
.c('value').t('none').up().up().up()
.c('field', {
'label': 'Roles for which Presence is Broadcasted',
'type': 'list-multi',
'var': 'muc#roomconfig_presencebroadcast'})
.c('value').t('moderator').up()
.c('value').t('participant').up()
.c('value').t('visitor').up()
.c('option', {'label': 'Moderator'})
.c('value').t('moderator').up().up()
.c('option', {'label': 'Participant'})
.c('value').t('participant').up().up()
.c('option', {'label': 'Visitor'})
.c('value').t('visitor').up().up().up()
.c('field', {
'label': 'Roles and Affiliations that May Retrieve Member List',
'type': 'list-multi',
'var': 'muc#roomconfig_getmemberlist'})
.c('value').t('moderator').up()
.c('value').t('participant').up()
.c('value').t('visitor').up()
.c('option', {'label': 'Moderator'})
.c('value').t('moderator').up().up()
.c('option', {'label': 'Participant'})
.c('value').t('participant').up().up()
.c('option', {'label': 'Visitor'})
.c('value').t('visitor').up().up().up()
.c('field', {
'label': 'Make Room Publicly Searchable?',
'type': 'boolean',
'var': 'muc#roomconfig_publicroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Publicly Searchable?',
'type': 'boolean',
'var': 'muc#roomconfig_publicroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Persistent?',
'type': 'boolean',
'var': 'muc#roomconfig_persistentroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Moderated?',
'type': 'boolean',
'var': 'muc#roomconfig_moderatedroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Members Only?',
'type': 'boolean',
'var': 'muc#roomconfig_membersonly'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Password Required for Entry?',
'type': 'boolean',
'var': 'muc#roomconfig_passwordprotectedroom'})
.c('value').t(1).up().up()
.c('field', {'type': 'fixed'})
.c('value').t('If a password is required to enter this room,'+
'you must specify the password below.').up().up()
.c('field', {
'label': 'Password',
'type': 'text-private',
'var': 'muc#roomconfig_roomsecret'})
.c('value').t('cauldronburn');
_converse.connection._dataRecv(test_utils.createRequest(config_stanza));
test_utils.waitUntil(function () { /* Check that an IQ is sent out, asking for the
return $(view.el.querySelector('form.chatroom-form')).length; * configuration form.
}, 300).then(function () { * See: // http://xmpp.org/extensions/xep-0045.html#example-163
expect($(view.el.querySelector('form.chatroom-form')).length).toBe(1); *
expect(view.el.querySelectorAll('form.chatroom-form fieldset').length).toBe(2); * <iq from='crone1@shakespeare.lit/desktop'
var $membersonly = $(view.el.querySelector('input[name="muc#roomconfig_membersonly"]')); * id='config1'
expect($membersonly.length).toBe(1); * to='coven@chat.shakespeare.lit'
expect($membersonly.attr('type')).toBe('checkbox'); * type='get'>
$membersonly.prop('checked', true); * <query xmlns='http://jabber.org/protocol/muc#owner'/>
* </iq>
*/
expect(sent_IQ.toLocaleString()).toBe(
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='http://jabber.org/protocol/muc#owner'/>"+
"</iq>");
var $moderated = $(view.el.querySelector('input[name="muc#roomconfig_moderatedroom"]')); /* Server responds with the configuration form.
expect($moderated.length).toBe(1); * See: // http://xmpp.org/extensions/xep-0045.html#example-165
expect($moderated.attr('type')).toBe('checkbox'); */
$moderated.prop('checked', true); var config_stanza = $iq({from: 'coven@chat.shakespeare.lit',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'result'})
.c('query', { 'xmlns': 'http://jabber.org/protocol/muc#owner'})
.c('x', { 'xmlns': 'jabber:x:data', 'type': 'form'})
.c('title').t('Configuration for "coven" Room').up()
.c('instructions').t('Complete this form to modify the configuration of your room.').up()
.c('field', {'type': 'hidden', 'var': 'FORM_TYPE'})
.c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up()
.c('field', {
'label': 'Natural-Language Room Name',
'type': 'text-single',
'var': 'muc#roomconfig_roomname'})
.c('value').t('A Dark Cave').up().up()
.c('field', {
'label': 'Short Description of Room',
'type': 'text-single',
'var': 'muc#roomconfig_roomdesc'})
.c('value').t('The place for all good witches!').up().up()
.c('field', {
'label': 'Enable Public Logging?',
'type': 'boolean',
'var': 'muc#roomconfig_enablelogging'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Allow Occupants to Change Subject?',
'type': 'boolean',
'var': 'muc#roomconfig_changesubject'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Allow Occupants to Invite Others?',
'type': 'boolean',
'var': 'muc#roomconfig_allowinvites'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Who Can Send Private Messages?',
'type': 'list-single',
'var': 'muc#roomconfig_allowpm'})
.c('value').t('anyone').up()
.c('option', {'label': 'Anyone'})
.c('value').t('anyone').up().up()
.c('option', {'label': 'Anyone with Voice'})
.c('value').t('participants').up().up()
.c('option', {'label': 'Moderators Only'})
.c('value').t('moderators').up().up()
.c('option', {'label': 'Nobody'})
.c('value').t('none').up().up().up()
.c('field', {
'label': 'Roles for which Presence is Broadcasted',
'type': 'list-multi',
'var': 'muc#roomconfig_presencebroadcast'})
.c('value').t('moderator').up()
.c('value').t('participant').up()
.c('value').t('visitor').up()
.c('option', {'label': 'Moderator'})
.c('value').t('moderator').up().up()
.c('option', {'label': 'Participant'})
.c('value').t('participant').up().up()
.c('option', {'label': 'Visitor'})
.c('value').t('visitor').up().up().up()
.c('field', {
'label': 'Roles and Affiliations that May Retrieve Member List',
'type': 'list-multi',
'var': 'muc#roomconfig_getmemberlist'})
.c('value').t('moderator').up()
.c('value').t('participant').up()
.c('value').t('visitor').up()
.c('option', {'label': 'Moderator'})
.c('value').t('moderator').up().up()
.c('option', {'label': 'Participant'})
.c('value').t('participant').up().up()
.c('option', {'label': 'Visitor'})
.c('value').t('visitor').up().up().up()
.c('field', {
'label': 'Make Room Publicly Searchable?',
'type': 'boolean',
'var': 'muc#roomconfig_publicroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Publicly Searchable?',
'type': 'boolean',
'var': 'muc#roomconfig_publicroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Persistent?',
'type': 'boolean',
'var': 'muc#roomconfig_persistentroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Moderated?',
'type': 'boolean',
'var': 'muc#roomconfig_moderatedroom'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Make Room Members Only?',
'type': 'boolean',
'var': 'muc#roomconfig_membersonly'})
.c('value').t(0).up().up()
.c('field', {
'label': 'Password Required for Entry?',
'type': 'boolean',
'var': 'muc#roomconfig_passwordprotectedroom'})
.c('value').t(1).up().up()
.c('field', {'type': 'fixed'})
.c('value').t('If a password is required to enter this room,'+
'you must specify the password below.').up().up()
.c('field', {
'label': 'Password',
'type': 'text-private',
'var': 'muc#roomconfig_roomsecret'})
.c('value').t('cauldronburn');
_converse.connection._dataRecv(test_utils.createRequest(config_stanza));
var $password = $(view.el.querySelector('input[name="muc#roomconfig_roomsecret"]')); test_utils.waitUntil(function () {
expect($password.length).toBe(1); return $(view.el.querySelector('form.chatroom-form')).length;
expect($password.attr('type')).toBe('password'); }, 300).then(function () {
expect($(view.el.querySelector('form.chatroom-form')).length).toBe(1);
expect(view.el.querySelectorAll('form.chatroom-form fieldset').length).toBe(2);
var $membersonly = $(view.el.querySelector('input[name="muc#roomconfig_membersonly"]'));
expect($membersonly.length).toBe(1);
expect($membersonly.attr('type')).toBe('checkbox');
$membersonly.prop('checked', true);
var $allowpm = $(view.el.querySelector('select[name="muc#roomconfig_allowpm"]')); var $moderated = $(view.el.querySelector('input[name="muc#roomconfig_moderatedroom"]'));
expect($allowpm.length).toBe(1); expect($moderated.length).toBe(1);
$allowpm.val('moderators'); expect($moderated.attr('type')).toBe('checkbox');
$moderated.prop('checked', true);
var $presencebroadcast = $(view.el.querySelector('select[name="muc#roomconfig_presencebroadcast"]')); var $password = $(view.el.querySelector('input[name="muc#roomconfig_roomsecret"]'));
expect($presencebroadcast.length).toBe(1); expect($password.length).toBe(1);
$presencebroadcast.val(['moderator']); expect($password.attr('type')).toBe('password');
view.el.querySelector('input[type="submit"]').click(); var $allowpm = $(view.el.querySelector('select[name="muc#roomconfig_allowpm"]'));
expect($allowpm.length).toBe(1);
$allowpm.val('moderators');
var $sent_stanza = $(sent_IQ.toLocaleString()); var $presencebroadcast = $(view.el.querySelector('select[name="muc#roomconfig_presencebroadcast"]'));
expect($sent_stanza.find('field[var="muc#roomconfig_membersonly"] value').text()).toBe('1'); expect($presencebroadcast.length).toBe(1);
expect($sent_stanza.find('field[var="muc#roomconfig_moderatedroom"] value').text()).toBe('1'); $presencebroadcast.val(['moderator']);
expect($sent_stanza.find('field[var="muc#roomconfig_allowpm"] value').text()).toBe('moderators');
expect($sent_stanza.find('field[var="muc#roomconfig_presencebroadcast"] value').text()).toBe('moderator'); view.el.querySelector('input[type="submit"]').click();
done();
var $sent_stanza = $(sent_IQ.toLocaleString());
expect($sent_stanza.find('field[var="muc#roomconfig_membersonly"] value').text()).toBe('1');
expect($sent_stanza.find('field[var="muc#roomconfig_moderatedroom"] value').text()).toBe('1');
expect($sent_stanza.find('field[var="muc#roomconfig_allowpm"] value').text()).toBe('moderators');
expect($sent_stanza.find('field[var="muc#roomconfig_presencebroadcast"] value').text()).toBe('moderator');
done();
});
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
})); }));
@ -1973,24 +1985,28 @@
var view = _converse.chatboxviews.get('lounge@localhost'), var view = _converse.chatboxviews.get('lounge@localhost'),
trimmed_chatboxes = _converse.minimized_chats; trimmed_chatboxes = _converse.minimized_chats;
spyOn(view, 'minimize').and.callThrough(); test_utils.waitUntil(function () {
spyOn(view, 'maximize').and.callThrough(); return !_.isNull(view.el.querySelector('.toggle-bookmark'));
spyOn(_converse, 'emit'); }, 300).then(function () {
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called spyOn(view, 'minimize').and.callThrough();
view.el.querySelector('.toggle-chatbox-button').click(); spyOn(view, 'maximize').and.callThrough();
spyOn(_converse, 'emit');
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
view.el.querySelector('.toggle-chatbox-button').click();
expect(view.minimize).toHaveBeenCalled(); expect(view.minimize).toHaveBeenCalled();
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
expect(u.isVisible(view.el)).toBeFalsy(); expect(u.isVisible(view.el)).toBeFalsy();
expect(view.model.get('minimized')).toBeTruthy(); expect(view.model.get('minimized')).toBeTruthy();
expect(view.minimize).toHaveBeenCalled(); expect(view.minimize).toHaveBeenCalled();
var trimmedview = trimmed_chatboxes.get(view.model.get('id')); var trimmedview = trimmed_chatboxes.get(view.model.get('id'));
trimmedview.el.querySelector("a.restore-chat").click(); trimmedview.el.querySelector("a.restore-chat").click();
expect(view.maximize).toHaveBeenCalled(); expect(view.maximize).toHaveBeenCalled();
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
expect(view.model.get('minimized')).toBeFalsy(); expect(view.model.get('minimized')).toBeFalsy();
expect(_converse.emit.calls.count(), 3); expect(_converse.emit.calls.count(), 3);
done(); done();
});
})); }));
it("can be closed again by clicking a DOM element with class 'close-chatbox-button'", it("can be closed again by clicking a DOM element with class 'close-chatbox-button'",
@ -2000,19 +2016,23 @@
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
var view = _converse.chatboxviews.get('lounge@localhost'); var view = _converse.chatboxviews.get('lounge@localhost');
spyOn(view, 'close').and.callThrough(); test_utils.waitUntil(function () {
spyOn(_converse, 'emit'); return !_.isNull(view.el.querySelector('.toggle-bookmark'));
spyOn(view, 'leave'); }, 300).then(function () {
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called spyOn(view, 'close').and.callThrough();
view.el.querySelector('.close-chatbox-button').click(); spyOn(_converse, 'emit');
expect(view.close).toHaveBeenCalled(); spyOn(view, 'leave');
expect(view.leave).toHaveBeenCalled(); view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
// XXX: After refactoring, the chat box only gets closed view.el.querySelector('.close-chatbox-button').click();
// once we have confirmation from the server. To test this, expect(view.close).toHaveBeenCalled();
// we would have to mock the returned presence stanza. expect(view.leave).toHaveBeenCalled();
// See the "leave" method on the ChatRoomView. // XXX: After refactoring, the chat box only gets closed
// expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object)); // once we have confirmation from the server. To test this,
done(); // we would have to mock the returned presence stanza.
// See the "leave" method on the ChatRoomView.
// expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
done();
});
})); }));
}); });

View File

@ -79,7 +79,7 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
var entities = _converse.disco_entities; var entities = _converse.disco_entities;
expect(entities.length).toBe(1); expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
expect(entities.get(_converse.domain).features.length).toBe(5); expect(entities.get(_converse.domain).features.length).toBe(5);
expect(entities.get(_converse.domain).identities.length).toBe(3); expect(entities.get(_converse.domain).identities.length).toBe(3);
expect(entities.get('localhost').features.where({'var': 'jabber:iq:version'}).length).toBe(1); expect(entities.get('localhost').features.where({'var': 'jabber:iq:version'}).length).toBe(1);
@ -159,7 +159,7 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
entities = _converse.disco_entities; entities = _converse.disco_entities;
expect(entities.length).toBe(4); expect(entities.length).toBe(5); // We have an extra entity, which is the user's JID
expect(entities.get(_converse.domain).identities.where({'category': 'conference'}).length).toBe(1); expect(entities.get(_converse.domain).identities.where({'category': 'conference'}).length).toBe(1);
expect(entities.get(_converse.domain).identities.where({'category': 'directory'}).length).toBe(1); expect(entities.get(_converse.domain).identities.where({'category': 'directory'}).length).toBe(1);
done(); done();

View File

@ -55,7 +55,7 @@
function (done, _converse) { function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza; var contact, sent_stanza, IQ_id, stanza;
test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp') test_utils.waitUntilFeatureSupportConfirmed(_converse, 'localhost', 'vcard-temp')
.then(function () { .then(function () {
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return _converse.xmppstatus.get('fullname'); return _converse.xmppstatus.get('fullname');

View File

@ -71,26 +71,33 @@
this.setBookmarkState(); this.setBookmarkState();
}, },
generateHeadingHTML () { renderHeading () {
const { _converse } = this.__super__, const { _converse } = this.__super__,
{ __ } = _converse, { __ } = _converse;
html = this.__super__.generateHeadingHTML.apply(this, arguments);
if (_converse.allow_bookmarks) { if (_converse.allow_bookmarks) {
const div = document.createElement('div'); _converse.api.disco.getIdentity('pubsub', 'pep', _converse.bare_jid).then((identity) => {
div.innerHTML = html; if (_.isNil(identity)) {
const bookmark_button = tpl_chatroom_bookmark_toggle( return;
_.assignIn( }
this.model.toJSON(), const div = document.createElement('div');
{ div.innerHTML = this.generateHeadingHTML();
info_toggle_bookmark: __('Bookmark this room'),
bookmarked: this.model.get('bookmarked') const bookmark_button = tpl_chatroom_bookmark_toggle(
} _.assignIn(
)); this.model.toJSON(),
const close_button = div.querySelector('.close-chatbox-button'); {
close_button.insertAdjacentHTML('afterend', bookmark_button); info_toggle_bookmark: __('Bookmark this room'),
return div.innerHTML; bookmarked: this.model.get('bookmarked')
}
));
const close_button = div.querySelector('.close-chatbox-button');
close_button.insertAdjacentHTML('afterend', bookmark_button);
this.el.querySelector('.chat-head-chatroom').innerHTML = div.innerHTML;
});
} else {
return this.__super__.renderHeading.apply(this, arguments);
} }
return html;
}, },
checkForReservedNick () { checkForReservedNick () {
@ -112,6 +119,9 @@
onBookmarked () { onBookmarked () {
const icon = this.el.querySelector('.icon-pushpin'); const icon = this.el.querySelector('.icon-pushpin');
if (_.isNull(icon)) {
return;
}
if (this.model.get('bookmarked')) { if (this.model.get('bookmarked')) {
icon.classList.add('button-on'); icon.classList.add('button-on');
} else { } else {
@ -520,14 +530,23 @@
if (!_converse.allow_bookmarks) { if (!_converse.allow_bookmarks) {
return; return;
} }
_converse.bookmarks = new _converse.Bookmarks(); // Only initialize bookmarks if the server supports PEP
_converse.bookmarks.fetchBookmarks().then(() => { _converse.api.disco.getIdentity('pubsub', 'pep', _converse.bare_jid).then((identity) => {
_converse.bookmarksview = new _converse.BookmarksView( if (_.isNil(identity)) {
{'model': _converse.bookmarks} _converse.emit('bookmarksInitialized');
); return;
}) }
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)) _converse.bookmarks = new _converse.Bookmarks();
.then(() => { _converse.bookmarks.fetchBookmarks().then(() => {
_converse.bookmarksview = new _converse.BookmarksView(
{'model': _converse.bookmarks}
);
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR))
.then(() => {
_converse.emit('bookmarksInitialized');
});
}).catch((e) => {
_converse.log(e, Strophe.LogLevel.ERROR);
_converse.emit('bookmarksInitialized'); _converse.emit('bookmarksInitialized');
}); });
}; };

View File

@ -1473,6 +1473,7 @@
this.connfeedback = new this.ConnectionFeedback(); this.connfeedback = new this.ConnectionFeedback();
this.XMPPStatus = Backbone.Model.extend({ this.XMPPStatus = Backbone.Model.extend({
initialize () { initialize () {
this.set({ this.set({
'status' : this.getStatus() 'status' : this.getStatus()

View File

@ -326,6 +326,9 @@
); );
} }
const promises = [_converse.api.waitUntil('roomsAutoJoined')] const promises = [_converse.api.waitUntil('roomsAutoJoined')]
if (_converse.allow_bookmarks) {
promises.push( _converse.api.waitUntil('bookmarksInitialized'));
}
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
_converse.api.rooms.open(jid); _converse.api.rooms.open(jid);
}); });

View File

@ -118,6 +118,14 @@
'debug': false 'debug': false
}, settings || {})); }, settings || {}));
_converse.ChatBoxViews.prototype.trimChat = function () {}; _converse.ChatBoxViews.prototype.trimChat = function () {};
var entity = _converse.api.disco.entities.get(_converse.bare_jid, true);
entity.identities.create({
'category': 'pubsub',
'type': 'pep'
});
entity.waitUntilFeaturesDiscovered.resolve();
window.converse_disable_effects = true; window.converse_disable_effects = true;
return _converse; return _converse;
} }

View File

@ -14,11 +14,12 @@
} }
utils.waitUntil = waitUntilPromise.default; utils.waitUntil = waitUntilPromise.default;
utils.waitUntilFeatureSupportConfirmed = function (_converse, feature_name) { utils.waitUntilFeatureSupportConfirmed = function (_converse, entity_jid, feature_name) {
var IQ_disco, stanza; var IQ_disco, stanza;
return utils.waitUntil(function () { return utils.waitUntil(function () {
IQ_disco = _.filter(_converse.connection.IQ_stanzas, function (iq) { IQ_disco = _.filter(_converse.connection.IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('query[xmlns="http://jabber.org/protocol/disco#info"]'); return iq.nodeTree.querySelector('query[xmlns="http://jabber.org/protocol/disco#info"]') &&
iq.nodeTree.getAttribute('to') === entity_jid;
}).pop(); }).pop();
return !_.isUndefined(IQ_disco); return !_.isUndefined(IQ_disco);
}, 300).then(function () { }, 300).then(function () {