Commit 5f3761dc authored by JC Brand's avatar JC Brand

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
parent bbe47b46
...@@ -12,6 +12,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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');
view.el.querySelector('.button-cancel').click(); $bookmark[0].click();
expect(view.closeForm).toHaveBeenCalled(); expect(view.renderBookmarkForm).toHaveBeenCalled();
expect($bookmark.hasClass('on-button'), false);
view.el.querySelector('.button-cancel').click();
$bookmark[0].click(); expect(view.closeForm).toHaveBeenCalled();
expect(view.renderBookmarkForm).toHaveBeenCalled(); expect($bookmark.hasClass('on-button'), false);
/* Client uploads data: $bookmark[0].click();
* -------------------- expect(view.renderBookmarkForm).toHaveBeenCalled();
* <iq from='juliet@capulet.lit/balcony' type='set' id='pip1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'> /* Client uploads data:
* <publish node='storage:bookmarks'> * --------------------
* <item id='current'> * <iq from='juliet@capulet.lit/balcony' type='set' id='pip1'>
* <storage xmlns='storage:bookmarks'> * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <conference name='The Play&apos;s the Thing' * <publish node='storage:bookmarks'>
* autojoin='true' * <item id='current'>
* jid='theplay@conference.shakespeare.lit'> * <storage xmlns='storage:bookmarks'>
* <nick>JC</nick> * <conference name='The Play&apos;s the Thing'
* </conference> * autojoin='true'
* </storage> * jid='theplay@conference.shakespeare.lit'>
* </item> * <nick>JC</nick>
* </publish> * </conference>
* <publish-options> * </storage>
* <x xmlns='jabber:x:data' type='submit'> * </item>
* <field var='FORM_TYPE' type='hidden'> * </publish>
* <value>http://jabber.org/protocol/pubsub#publish-options</value> * <publish-options>
* </field> * <x xmlns='jabber:x:data' type='submit'>
* <field var='pubsub#persist_items'> * <field var='FORM_TYPE' type='hidden'>
* <value>true</value> * <value>http://jabber.org/protocol/pubsub#publish-options</value>
* </field> * </field>
* <field var='pubsub#access_model'> * <field var='pubsub#persist_items'>
* <value>whitelist</value> * <value>true</value>
* </field> * </field>
* </x> * <field var='pubsub#access_model'>
* </publish-options> * <value>whitelist</value>
* </pubsub> * </field>
* </iq> * </x>
*/ * </publish-options>
expect(view.model.get('bookmarked')).toBeFalsy(); * </pubsub>
var $form = $(view.el).find('.chatroom-form'); * </iq>
$form.find('input[name="name"]').val('Play&apos;s the Thing'); */
$form.find('input[name="autojoin"]').prop('checked', true); expect(view.model.get('bookmarked')).toBeFalsy();
$form.find('input[name="nick"]').val('JC'); var $form = $(view.el).find('.chatroom-form');
view.el.querySelector('.button-primary').click(); $form.find('input[name="name"]').val('Play&apos;s the Thing');
$form.find('input[name="autojoin"]').prop('checked', true);
expect(view.model.get('bookmarked')).toBeTruthy(); $form.find('input[name="nick"]').val('JC');
expect($bookmark.hasClass('on-button'), true); view.el.querySelector('.button-primary').click();
expect(sent_stanza.toLocaleString()).toBe( expect(view.model.get('bookmarked')).toBeTruthy();
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+ expect($bookmark.hasClass('on-button'), true);
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<publish node='storage:bookmarks'>"+ expect(sent_stanza.toLocaleString()).toBe(
"<item id='current'>"+ "<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<storage xmlns='storage:bookmarks'>"+ "<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<conference name='Play&amp;apos;s the Thing' autojoin='true' jid='theplay@conference.shakespeare.lit'>"+ "<publish node='storage:bookmarks'>"+
"<nick>JC</nick>"+ "<item id='current'>"+
"</conference>"+ "<storage xmlns='storage:bookmarks'>"+
"</storage>"+ "<conference name='Play&amp;apos;s the Thing' autojoin='true' jid='theplay@conference.shakespeare.lit'>"+
"</item>"+ "<nick>JC</nick>"+
"</publish>"+ "</conference>"+
"<publish-options>"+ "</storage>"+
"<x xmlns='jabber:x:data' type='submit'>"+ "</item>"+
"<field var='FORM_TYPE' type='hidden'>"+ "</publish>"+
"<value>http://jabber.org/protocol/pubsub#publish-options</value>"+ "<publish-options>"+
"</field>"+ "<x xmlns='jabber:x:data' type='submit'>"+
"<field var='pubsub#persist_items'>"+ "<field var='FORM_TYPE' type='hidden'>"+
"<value>true</value>"+ "<value>http://jabber.org/protocol/pubsub#publish-options</value>"+
"</field>"+ "</field>"+
"<field var='pubsub#access_model'>"+ "<field var='pubsub#persist_items'>"+
"<value>whitelist</value>"+ "<value>true</value>"+
"</field>"+ "</field>"+
"</x>"+ "<field var='pubsub#access_model'>"+
"</publish-options>"+ "<value>whitelist</value>"+
"</pubsub>"+ "</field>"+
"</iq>" "</x>"+
); "</publish-options>"+
"</pubsub>"+
/* Server acknowledges successful storage "</iq>"
* );
* <iq to='juliet@capulet.lit/balcony' type='result' id='pip1'/>
*/ /* Server acknowledges successful storage
var stanza = $iq({ *
'to':_converse.connection.jid, * <iq to='juliet@capulet.lit/balcony' type='result' id='pip1'/>
'type':'result', */
'id':IQ_id var stanza = $iq({
'to':_converse.connection.jid,
'type':'result',
'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 @@ ...@@ -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 @@ ...@@ -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.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) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
$bookmark_icon[0].click();
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
// conferences to bookmark (since we removed the one and
// only bookmark).
expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<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();
}); });
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
$bookmark_icon[0].click();
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
// conferences to bookmark (since we removed the one and
// only bookmark).
expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<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 @@ ...@@ -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
* -------------------------
*
* <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <items node='storage:bookmarks'/>
* </pubsub>
* </iq>
*/
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);
/*
* 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); test_utils.waitUntil(function () {
return _converse.bookmarks;
}, 300).then(function () {
/* Client requests all items
* -------------------------
*
* <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <items node='storage:bookmarks'/>
* </pubsub>
* </iq>
*/
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 @@ ...@@ -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 @@ ...@@ -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( test_utils.openControlBox().openRoomsPanel(_converse);
"1st Bookmark  Another room  Bookmark with a very very long name that will be shortened  The Play&apos;s the Thing") var IQ_id;
expect(_.filter(_converse.connection.send.calls.all(), function (call) {
spyOn(window, 'confirm').and.returnValue(true); var stanza = call.args[0];
$('#chatrooms dl.bookmarks dd:nth-child(2) a:nth-child(2)')[0].click(); if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
expect(window.confirm).toHaveBeenCalled(); return;
}
return test_utils.waitUntil(function () { // XXX: Wrapping in a div is a workaround for PhantomJS
return $('#chatrooms dl.bookmarks dd a').text().trim() === var div = document.createElement('div');
"1st Bookmark  Bookmark with a very very long name that will be shortened  The Play&apos;s the Thing"; div.appendChild(stanza);
}, 300) if (div.innerHTML ===
}).then(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'})
.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 @@ ...@@ -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}
// Check that it's there );
var jid = 'room@conference.example.org'; _converse.emit('bookmarksInitialized');
_converse.bookmarks.create({
'jid': jid,
'autojoin': false,
'name': 'The Play',
'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1); // Check that it's there
var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room"); var jid = 'room@conference.example.org';
expect(room_els.length).toBe(1); _converse.bookmarks.create({
'jid': jid,
'autojoin': false,
'name': 'The Play',
'nick': ' Othello'
});
// Check that it disappears once the room is opened expect(_converse.bookmarks.length).toBe(1);
var bookmark = _converse.bookmarksview.el.querySelector(".open-room"); var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
bookmark.click(); expect(room_els.length).toBe(1);
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
// Check that it reappears once the room is closed // Check that it disappears once the room is opened
var view = _converse.chatboxviews.get(jid); var bookmark = _converse.bookmarksview.el.querySelector(".open-room");
view.close(); bookmark.click();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy(); expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
done(); // 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();
});
})); }));
}); });
})); }));
...@@ -57,7 +57,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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');
......
...@@ -762,7 +762,6 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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
* configuration form.
* See: // http://xmpp.org/extensions/xep-0045.html#example-163
*
* <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.
* 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 () { test_utils.waitUntil(function () {
return $(view.el.querySelector('form.chatroom-form')).length; return !_.isNull(view.el.querySelector('.configure-chatroom-button'));
}, 300).then(function () { }, 300).then(function () {
expect($(view.el.querySelector('form.chatroom-form')).length).toBe(1); expect($(view.el.querySelector('.configure-chatroom-button')).is(':visible')).toBeTruthy();
expect(view.el.querySelectorAll('form.chatroom-form fieldset').length).toBe(2);
var $membersonly = $(view.el.querySelector('input[name="muc#roomconfig_membersonly"]')); view.el.querySelector('.configure-chatroom-button').click();
expect($membersonly.length).toBe(1);
expect($membersonly.attr('type')).toBe('checkbox'); /* Check that an IQ is sent out, asking for the
$membersonly.prop('checked', true); * configuration form.
* See: // http://xmpp.org/extensions/xep-0045.html#example-163
var $moderated = $(view.el.querySelector('input[name="muc#roomconfig_moderatedroom"]')); *
expect($moderated.length).toBe(1); * <iq from='crone1@shakespeare.lit/desktop'
expect($moderated.attr('type')).toBe('checkbox'); * id='config1'
$moderated.prop('checked', true); * to='coven@chat.shakespeare.lit'
* type='get'>
var $password = $(view.el.querySelector('input[name="muc#roomconfig_roomsecret"]')); * <query xmlns='http://jabber.org/protocol/muc#owner'/>
expect($password.length).toBe(1); * </iq>
expect($password.attr('type')).toBe('password'); */
expect(sent_IQ.toLocaleString()).toBe(
var $allowpm = $(view.el.querySelector('select[name="muc#roomconfig_allowpm"]')); "<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
expect($allowpm.length).toBe(1); "<query xmlns='http://jabber.org/protocol/muc#owner'/>"+
$allowpm.val('moderators'); "</iq>");
var $presencebroadcast = $(view.el.querySelector('select[name="muc#roomconfig_presencebroadcast"]')); /* Server responds with the configuration form.
expect($presencebroadcast.length).toBe(1); * See: // http://xmpp.org/extensions/xep-0045.html#example-165
$presencebroadcast.val(['moderator']); */
var config_stanza = $iq({from: 'coven@chat.shakespeare.lit',
view.el.querySelector('input[type="submit"]').click(); 'id': IQ_id,
'to': 'dummy@localhost/desktop',
var $sent_stanza = $(sent_IQ.toLocaleString()); 'type': 'result'})
expect($sent_stanza.find('field[var="muc#roomconfig_membersonly"] value').text()).toBe('1'); .c('query', { 'xmlns': 'http://jabber.org/protocol/muc#owner'})
expect($sent_stanza.find('field[var="muc#roomconfig_moderatedroom"] value').text()).toBe('1'); .c('x', { 'xmlns': 'jabber:x:data', 'type': 'form'})
expect($sent_stanza.find('field[var="muc#roomconfig_allowpm"] value').text()).toBe('moderators'); .c('title').t('Configuration for "coven" Room').up()
expect($sent_stanza.find('field[var="muc#roomconfig_presencebroadcast"] value').text()).toBe('moderator'); .c('instructions').t('Complete this form to modify the configuration of your room.').up()
done(); .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 () {
return $(view.el.querySelector('form.chatroom-form')).length;
}, 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 $moderated = $(view.el.querySelector('input[name="muc#roomconfig_moderatedroom"]'));
expect($moderated.length).toBe(1);
expect($moderated.attr('type')).toBe('checkbox');
$moderated.prop('checked', true);
var $password = $(view.el.querySelector('input[name="muc#roomconfig_roomsecret"]'));
expect($password.length).toBe(1);
expect($password.attr('type')).toBe('password');
var $allowpm = $(view.el.querySelector('select[name="muc#roomconfig_allowpm"]'));
expect($allowpm.length).toBe(1);
$allowpm.val('moderators');
var $presencebroadcast = $(view.el.querySelector('select[name="muc#roomconfig_presencebroadcast"]'));
expect($presencebroadcast.length).toBe(1);
$presencebroadcast.val(['moderator']);
view.el.querySelector('input[type="submit"]').click();
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 @@ ...@@ -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');
expect(view.minimize).toHaveBeenCalled(); view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); view.el.querySelector('.toggle-chatbox-button').click();
expect(u.isVisible(view.el)).toBeFalsy();
expect(view.model.get('minimized')).toBeTruthy(); expect(view.minimize).toHaveBeenCalled();
expect(view.minimize).toHaveBeenCalled(); expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
var trimmedview = trimmed_chatboxes.get(view.model.get('id')); expect(u.isVisible(view.el)).toBeFalsy();
trimmedview.el.querySelector("a.restore-chat").click(); expect(view.model.get('minimized')).toBeTruthy();
expect(view.maximize).toHaveBeenCalled(); expect(view.minimize).toHaveBeenCalled();
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); var trimmedview = trimmed_chatboxes.get(view.model.get('id'));
expect(view.model.get('minimized')).toBeFalsy(); trimmedview.el.querySelector("a.restore-chat").click();
expect(_converse.emit.calls.count(), 3); expect(view.maximize).toHaveBeenCalled();
done(); expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
expect(view.model.get('minimized')).toBeFalsy();
expect(_converse.emit.calls.count(), 3);
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 @@ ...@@ -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();
});
})); }));
}); });
......
...@@ -79,7 +79,7 @@ ...@@ -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 @@ ...@@ -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();
......
...@@ -55,7 +55,7 @@ ...@@ -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');
......
...@@ -71,26 +71,33 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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');
}); });
}; };
......
...@@ -1473,6 +1473,7 @@ ...@@ -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()
......
...@@ -326,6 +326,9 @@ ...@@ -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);
}); });
......
...@@ -118,6 +118,14 @@ ...@@ -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;
} }
......
...@@ -14,11 +14,12 @@ ...@@ -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 () {
......
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