Use promises to determine when to create the controlbox

This commit is contained in:
JC Brand 2017-08-16 12:31:17 +02:00
parent 956340aa8c
commit 694eabfc0e
6 changed files with 163 additions and 90 deletions

View File

@ -3,20 +3,42 @@
} (this, function ($, jasmine, mock, converse, test_utils) {
var Strophe = converse.env.Strophe;
var $iq = converse.env.$iq;
var _ = converse.env._;
describe("The Registration Panel", function () {
it("is not available unless allow_registration=true", mock.initConverse(function (_converse) {
it("is not available unless allow_registration=true",
mock.initConverseWithPromises(
null, ['connectionInitialized', 'chatBoxesInitialized'],
{ auto_login: false,
allow_registration: false },
function (done, _converse) {
test_utils.waitUntil(function () {
return _converse.chatboxviews.get('controlbox');
}, 300)
.then(function () {
test_utils.openControlBox();
var cbview = _converse.chatboxviews.get('controlbox');
expect(cbview.$('#controlbox-tabs li').length).toBe(1);
expect(cbview.$('#controlbox-tabs li').text().trim()).toBe("Sign in");
}, { auto_login: false,
allow_registration: false,
done();
});
}));
it("can be opened by clicking on the registration tab", mock.initConverse(function (_converse) {
it("can be opened by clicking on the registration tab",
mock.initConverseWithPromises(
null, ['connectionInitialized', 'chatBoxesInitialized'],
{ auto_login: false,
allow_registration: true },
function (done, _converse) {
test_utils.waitUntil(function () {
return _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel');
}, 300)
.then(function () {
var cbview = _converse.chatboxviews.get('controlbox');
test_utils.openControlBox();
var $tabs = cbview.$('#controlbox-tabs');
@ -32,12 +54,22 @@
expect($login.is(':visible')).toBe(false);
expect($registration.is(':visible')).toBe(true);
expect(cbview.switchTab).toHaveBeenCalled();
}, { auto_login: false,
allow_registration: true,
done();
});
}));
it("allows the user to choose an XMPP provider's domain", mock.initConverse(function (_converse) {
it("allows the user to choose an XMPP provider's domain",
mock.initConverseWithPromises(
null, ['connectionInitialized', 'chatBoxesInitialized'],
{ auto_login: false,
allow_registration: true },
function (done, _converse) {
test_utils.waitUntil(function () {
return _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel');
}, 300)
.then(function () {
var cbview = _converse.chatboxviews.get('controlbox');
var registerview = cbview.registerpanel;
spyOn(registerview, 'onProviderChosen').and.callThrough();
@ -59,11 +91,22 @@
$form.find('input[type=submit]').click();
expect(registerview.onProviderChosen).toHaveBeenCalled();
expect(_converse.connection.connect).toHaveBeenCalled();
}, { auto_login: false,
allow_registration: true,
}));
done();
});
}));
it("will render a registration form as received from the XMPP provider",
mock.initConverseWithPromises(
null, ['connectionInitialized', 'chatBoxesInitialized'],
{ auto_login: false,
allow_registration: true },
function (done, _converse) {
test_utils.waitUntil(function () {
return _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel');
}, 300)
.then(function () {
it("will render a registration form as received from the XMPP provider", mock.initConverse(function (_converse) {
var cbview = _converse.chatboxviews.get('controlbox');
cbview.$('#controlbox-tabs').find('li').last().find('a').click(); // Click the Register tab
var registerview = _converse.chatboxviews.get('controlbox').registerpanel;
@ -107,14 +150,25 @@
expect(registerview.$('input').length).toBe(5);
expect(registerview.$('input[type=submit]').length).toBe(1);
expect(registerview.$('input[type=button]').length).toBe(1);
}, { auto_login: false,
allow_registration: true,
}));
done();
});
}));
it("will set form_type to legacy and submit it as legacy",
mock.initConverseWithPromises(
null, ['connectionInitialized', 'chatBoxesInitialized'],
{ auto_login: false,
allow_registration: true },
function (done, _converse) {
test_utils.waitUntil(function () {
return _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel');
}, 300)
.then(function () {
it("will set form_type to legacy and submit it as legacy", mock.initConverse(function (_converse) {
var cbview = _converse.chatboxviews.get('controlbox');
cbview.$('#controlbox-tabs').find('li').last().find('a').click(); // Click the Register tab
var registerview = _converse.chatboxviews.get('controlbox').registerpanel;
var registerview = cbview.registerpanel;
spyOn(registerview, 'onProviderChosen').and.callThrough();
spyOn(registerview, 'getRegistrationFields').and.callThrough();
spyOn(registerview, 'onRegistrationFields').and.callThrough();
@ -156,11 +210,22 @@
var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
expect($stanza.children('query').children().length).toBe(3);
expect($stanza.children('query').children()[0].tagName).toBe('username');
}, { auto_login: false,
allow_registration: true,
}));
done();
});
}));
it("will set form_type to xform and submit it as xform",
mock.initConverseWithPromises(
null, ['connectionInitialized', 'chatBoxesInitialized'],
{ auto_login: false,
allow_registration: true },
function (done, _converse) {
test_utils.waitUntil(function () {
return _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel');
}, 300)
.then(function () {
it("will set form_type to xform and submit it as xform", mock.initConverse(function (_converse) {
var cbview = _converse.chatboxviews.get('controlbox');
cbview.$('#controlbox-tabs').find('li').last().find('a').click(); // Click the Register tab
var registerview = _converse.chatboxviews.get('controlbox').registerpanel;
@ -208,8 +273,8 @@
expect($stanza.children('query').children().length).toBe(1);
expect($stanza.children('query').children().children().length).toBe(3);
expect($stanza.children('query').children().children()[0].tagName).toBe('field');
}, { auto_login: false,
allow_registration: true,
}));
done();
});
}));
});
}));

View File

@ -50,7 +50,10 @@
*/
const { _converse } = this;
_converse.api.promises.add('chatBoxesFetched');
_converse.api.promises.add([
'chatBoxesFetched',
'chatBoxesInitialized'
]);
_converse.ChatBoxes = Backbone.Collection.extend({
comparator: 'time_opened',
@ -312,15 +315,20 @@
}
});
_converse.chatboxes = new _converse.ChatBoxes();
_converse.chatboxviews = new _converse.ChatBoxViews({
'model': this.chatboxes
// BEGIN: Event handlers
_converse.api.listen.on('pluginsInitialized', () => {
_converse.chatboxes = new _converse.ChatBoxes();
_converse.chatboxviews = new _converse.ChatBoxViews({
'model': _converse.chatboxes
});
_converse.emit('chatBoxesInitialized');
});
_converse.api.listen.on('beforeTearDown', () => {
this.chatboxes.remove(); // Don't call off(), events won't get re-registered upon reconnect.
delete this.chatboxes.browserStorage;
});
// END: Event handlers
_converse.getViewForChatBox = function (chatbox) {
if (!chatbox) { return; }
@ -331,7 +339,6 @@
_.extend(_converse.api, {
'chats': {
'open' (jids, attrs) {
debugger;
if (_.isUndefined(jids)) {
_converse.log("chats.open: You need to provide at least one JID", Strophe.LogLevel.ERROR);
return null;

View File

@ -48,7 +48,7 @@
const USERS_PANEL_ID = 'users';
const CHATBOX_TYPE = 'chatbox';
const { Strophe, Backbone, utils, _, moment } = converse.env;
const { Strophe, Backbone, Promise, utils, _, moment } = converse.env;
converse.plugins.add('converse-controlbox', {
@ -60,18 +60,6 @@
//
// New functions which don't exist yet can also be added.
initChatBoxes () {
this.__super__.initChatBoxes.apply(this, arguments);
this.controlboxtoggle = new this.ControlBoxToggle();
},
initConnection () {
this.__super__.initConnection.apply(this, arguments);
if (this.connection) {
this.addControlBox();
}
},
_tearDown () {
this.__super__._tearDown.apply(this, arguments);
if (this.rosterview) {
@ -215,6 +203,7 @@
},
initialize () {
_converse.controlboxtoggle = new _converse.ControlBoxToggle();
this.$el.insertAfter(_converse.controlboxtoggle.$el);
this.model.on('change:connected', this.onConnected, this);
this.model.on('destroy', this.hide, this);
@ -222,9 +211,9 @@
this.model.on('show', this.show, this);
this.model.on('change:closed', this.ensureClosedState, this);
this.render();
if (this.model.get('connected')) {
this.insertRoster();
}
_converse.api.waitUntil('rosterViewInitialized')
.then(this.insertRoster.bind(this))
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
},
render () {
@ -256,7 +245,10 @@
onConnected () {
if (this.model.get('connected')) {
this.render().insertRoster();
this.render();
_converse.api.waitUntil('rosterViewInitialized')
.then(this.insertRoster.bind(this))
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
this.model.save();
}
},
@ -732,7 +724,7 @@
},
initialize () {
_converse.chatboxviews.$el.prepend(this.render());
_converse.chatboxviews.$el.prepend(this.render().el);
this.updateOnlineCount();
const that = this;
_converse.api.waitUntil('initialized').then(() => {
@ -748,11 +740,10 @@
// the ControlBox or the Toggle must be shown. This prevents
// artifacts (i.e. on page load the toggle is shown only to then
// seconds later be hidden in favor of the control box).
return this.$el.html(
tpl_controlbox_toggle({
'label_toggle': __('Toggle chat')
})
);
this.el.innerHTML = tpl_controlbox_toggle({
'label_toggle': __('Toggle chat')
})
return this;
},
updateOnlineCount: _.debounce(function () {
@ -802,6 +793,12 @@
}
});
Promise.all([
_converse.api.waitUntil('connectionInitialized'),
_converse.api.waitUntil('chatBoxesInitialized')
]).then(_converse.addControlBox)
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
const disconnect = function () {
/* Upon disconnection, set connected to `false`, so that if
* we reconnect,

View File

@ -152,6 +152,7 @@
const PROMISES = [
'initialized',
'cachedRoster',
'connectionInitialized',
'pluginsInitialized',
'roster',
'rosterContactsFetched',
@ -575,11 +576,11 @@
});
this.initSession = function () {
this.session = new Backbone.Model();
_converse.session = new Backbone.Model();
const id = b64_sha1('converse.bosh-session');
this.session.id = id; // Appears to be necessary for backbone.browserStorage
this.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
this.session.fetch();
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
_converse.session.fetch();
};
this.clearSession = function () {
@ -1778,22 +1779,22 @@
};
this.initConnection = function () {
if (this.connection) {
return;
}
if (!this.bosh_service_url && ! this.websocket_url) {
throw new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
}
if (('WebSocket' in window || 'MozWebSocket' in window) && this.websocket_url) {
this.connection = new Strophe.Connection(this.websocket_url, this.connection_options);
} else if (this.bosh_service_url) {
this.connection = new Strophe.Connection(
this.bosh_service_url,
_.assignIn(this.connection_options, {'keepalive': this.keepalive})
);
} else {
throw new Error("initConnection: this browser does not support websockets and bosh_service_url wasn't specified.");
if (!this.connection) {
if (!this.bosh_service_url && ! this.websocket_url) {
throw new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
}
if (('WebSocket' in window || 'MozWebSocket' in window) && this.websocket_url) {
this.connection = new Strophe.Connection(this.websocket_url, this.connection_options);
} else if (this.bosh_service_url) {
this.connection = new Strophe.Connection(
this.bosh_service_url,
_.assignIn(this.connection_options, {'keepalive': this.keepalive})
);
} else {
throw new Error("initConnection: this browser does not support websockets and bosh_service_url wasn't specified.");
}
}
_converse.emit('connectionInitialized');
};
this._tearDown = function () {
@ -1801,11 +1802,13 @@
* connection.
*/
_converse.emit('beforeTearDown');
this.unregisterPresenceHandler();
if (this.roster) {
this.roster.off().reset(); // Removes roster contacts
_converse.unregisterPresenceHandler();
if (_converse.roster) {
_converse.roster.off().reset(); // Removes roster contacts
}
if (!_.isUndefined(_converse.session)) {
_converse.session.destroy();
}
this.session.destroy();
window.removeEventListener('click', _converse.onUserActivity);
window.removeEventListener('focus', _converse.onUserActivity);
window.removeEventListener('keypress', _converse.onUserActivity);
@ -1813,7 +1816,7 @@
window.removeEventListener(unloadevent, _converse.onUserActivity);
window.clearInterval(_converse.everySecondTrigger);
_converse.emit('afterTearDown');
return this;
return _converse;
};
this.initPlugins = function () {

View File

@ -27,7 +27,7 @@
) {
"use strict";
const { _ , utils, Backbone, b64_sha1, moment } = converse.env;
const { _ , utils, Backbone, Promise, Strophe, b64_sha1, moment } = converse.env;
converse.plugins.add('converse-minimize', {
overrides: {
@ -37,15 +37,6 @@
//
// New functions which don't exist yet can also be added.
initChatBoxes () {
const { _converse } = this.__super__;
const result = this.__super__.initChatBoxes.apply(this, arguments);
_converse.minimized_chats = new _converse.MinimizedChats({
model: _converse.chatboxes
});
return result;
},
registerGlobalEventHandlers () {
const { _converse } = this.__super__;
$(window).on("resize", _.debounce(function (ev) {
@ -492,7 +483,16 @@
}
});
const renderMinimizeButton = function (view) {
Promise.all([
_converse.api.waitUntil('connectionInitialized'),
_converse.api.waitUntil('chatBoxesInitialized')
]).then(() => {
_converse.minimized_chats = new _converse.MinimizedChats({
model: _converse.chatboxes
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
_converse.on('chatBoxOpened', function renderMinimizeButton (view) {
// Inserts a "minimize" button in the chatview's header
const $el = view.$el.find('.toggle-chatbox-button');
const $new_el = tpl_chatbox_minimize(
@ -503,8 +503,7 @@
} else {
view.$el.find('.close-chatbox-button').after($new_el);
}
};
_converse.on('chatBoxOpened', renderMinimizeButton);
});
_converse.on('controlBoxOpened', function (chatbox) {
// Wrapped in anon method because at scan time, chatboxviews

View File

@ -76,6 +76,7 @@
allow_contact_removal: true,
show_toolbar: true,
});
_converse.api.promises.add('rosterViewInitialized');
const STATUSES = {
'dnd': __('This contact is busy'),
@ -950,6 +951,7 @@
'model': _converse.rostergroups
});
_converse.rosterview.render();
_converse.emit('rosterViewInitialized');
};
_converse.api.listen.on('rosterInitialized', initRoster);
_converse.api.listen.on('rosterReadyAfterReconnection', initRoster);