Commit 725a382e authored by JC Brand's avatar JC Brand

Refactor initialization and defaults for chat boxes

- Let box_id start with char for valid HTML.
- No need to use SHA1 for box id
- No need for the user_id attribute.
- Set nickname when we set the roster contact.

Also...

- _converse.api.contacts.get is now async
- _converse.api.chats.create is now async
parent 7c5bbfbe
......@@ -17,6 +17,7 @@
this was the default behavior.
- `_converse.api.emit` has been removed in favor of [\_converse.api.trigger](https://conversejs.org/docs/html/api/-_converse.api.html#.trigger)
- `_converse.updateSettings` has been removed in favor of [\_converse.api.settings.update](https://conversejs.org/docs/html/api/-_converse.api.settings.html#.update)
- `_converse.api.roster.get` now returns a promise.
## 4.2.0 (2019-04-04)
......
This diff is collapsed.
......@@ -241,9 +241,8 @@
await test_utils.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const chat = _converse.api.chats.create(sender_jid, {
minimized: true
});
const chat = await _converse.api.chats.create(sender_jid, {'minimized': true});
await test_utils.waitUntil(() => _converse.chatboxes.length > 1);
const chatBoxView = _converse.chatboxviews.get(sender_jid);
expect(u.isVisible(chatBoxView.el)).toBeFalsy();
......@@ -1389,7 +1388,7 @@
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread too');
await _converse.chatboxes.onMessage(msg);
await test_utils.waitUntil(() => chatbox.messages.length > 1);
await test_utils.waitUntil(() => chatbox.messages.length === 2);
indicator_el = sizzle(selector, _converse.rosterview.el).pop();
expect(indicator_el.textContent).toBe('2');
done();
......
......@@ -247,23 +247,24 @@
describe("The \"contacts\" API", function () {
it("has a method 'get' which returns wrapped contacts", mock.initConverse((done, _converse) => {
it("has a method 'get' which returns wrapped contacts", mock.initConverse(async (done, _converse) => {
// Check that it returns nothing if a non-existing JID is given
test_utils.createContacts(_converse, 'current');
expect(_converse.api.contacts.get('non-existing@jabber.org')).toBeFalsy();
let contact = await _converse.api.contacts.get('non-existing@jabber.org');
expect(contact).toBeFalsy();
// Check when a single jid is given
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const contact = _converse.api.contacts.get(jid);
contact = await _converse.api.contacts.get(jid);
expect(contact.get('fullname')).toBe(mock.cur_names[0]);
expect(contact.get('jid')).toBe(jid);
// You can retrieve multiple contacts by passing in an array
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
let list = _converse.api.contacts.get([jid, jid2]);
let list = await _converse.api.contacts.get([jid, jid2]);
expect(_.isArray(list)).toBeTruthy();
expect(list[0].get('fullname')).toBe(mock.cur_names[0]);
expect(list[1].get('fullname')).toBe(mock.cur_names[1]);
// Check that all JIDs are returned if you call without any parameters
list = _converse.api.contacts.get();
list = await _converse.api.contacts.get();
expect(list.length).toBe(mock.cur_names.length);
done();
}));
......@@ -301,11 +302,9 @@
expect(_converse.chatboxes.length).toBe(1);
// Test for one JID
test_utils.openChatBoxFor(_converse, jid);
await test_utils.waitUntil(() => _converse.chatboxes.length == 1);
box = _converse.api.chats.get(jid);
box = await _converse.api.chats.open(jid);
expect(box instanceof Object).toBeTruthy();
expect(box.get('box_id')).toBe(b64_sha1(jid));
expect(box.get('box_id')).toBe(`box-${btoa(jid)}`);
const chatboxview = _converse.chatboxviews.get(jid);
expect(u.isVisible(chatboxview.el)).toBeTruthy();
......@@ -314,8 +313,8 @@
await test_utils.waitUntil(() => _converse.chatboxes.length == 2);
const list = _converse.api.chats.get([jid, jid2]);
expect(_.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(b64_sha1(jid));
expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
done();
}));
......@@ -334,7 +333,7 @@
const box = await _converse.api.chats.open(jid);
expect(box instanceof Object).toBeTruthy();
expect(box.get('box_id')).toBe(b64_sha1(jid));
expect(box.get('box_id')).toBe(`box-${btoa(jid)}`);
expect(
_.keys(box),
['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
......@@ -344,8 +343,8 @@
// Test for multiple JIDs
const list = await _converse.api.chats.open([jid, jid2]);
expect(_.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(b64_sha1(jid));
expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
done();
}));
});
......
......@@ -741,7 +741,7 @@
let msg_obj = chatbox.messages.models[0];
expect(msg_obj.get('message')).toEqual(message);
expect(msg_obj.get('fullname')).toBeUndefined();
expect(msg_obj.get('nickname')).toBeUndefined();
expect(msg_obj.get('nickname')).toBe(null);
expect(msg_obj.get('sender')).toEqual('them');
expect(msg_obj.get('is_delayed')).toEqual(true);
await test_utils.waitUntil(() => chatbox.vcard.get('fullname') === 'Candice van der Knijff')
......
......@@ -24,9 +24,8 @@
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntil(() => _converse.chatboxes.length);
await test_utils.waitUntil(() => _converse.chatboxes.length > 1);
const view = _converse.chatboxviews.get(contact_jid);
await new Promise((resolve) => view.model.once('contactAdded', resolve));
let show_modal_button = view.el.querySelector('.show-user-details-modal');
expect(u.isVisible(show_modal_button)).toBeTruthy();
show_modal_button.click();
......
......@@ -23,17 +23,17 @@ const AvatarMixin = {
if (_.isNull(canvas_el)) {
return;
}
if (this.model.vcard) {
const data = {
'classes': canvas_el.getAttribute('class'),
'width': canvas_el.width,
'height': canvas_el.height,
}
if (this.model.vcard) {
const image_type = this.model.vcard.get('image_type'),
image = this.model.vcard.get('image');
data['image'] = "data:" + image_type + ";base64," + image;
}
canvas_el.outerHTML = tpl_avatar(data);
}
},
};
......@@ -143,7 +143,7 @@ converse.plugins.add('converse-chatboxviews', {
/* This method gets overridden in src/converse-controlbox.js if
* the controlbox plugin is active.
*/
this.each(function (view) { view.close(); });
this.each(v => v.close());
return this;
}
});
......
......@@ -163,7 +163,9 @@ converse.plugins.add('converse-chatview', {
this.model.on('change:status', this.onStatusMessageChanged, this);
this.debouncedRender = _.debounce(this.render, 50);
if (this.model.vcard) {
this.model.vcard.on('change', this.debouncedRender, this);
}
this.model.on('rosterContactAdded', () => {
this.model.contact.on('change:nickname', this.debouncedRender, this);
this.debouncedRender();
......@@ -171,9 +173,11 @@ converse.plugins.add('converse-chatview', {
},
render () {
const vcard = _.get(this.model, 'vcard'),
vcard_json = vcard ? vcard.toJSON() : {};
this.el.innerHTML = tpl_chatbox_head(
_.extend(
this.model.vcard.toJSON(),
vcard_json,
this.model.toJSON(),
{ '_converse': _converse,
'info_close': __('Close this chat box'),
......@@ -213,7 +217,7 @@ converse.plugins.add('converse-chatview', {
initialize () {
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
this.model.on('contactAdded', this.registerContactEventHandlers, this);
this.model.on('rosterContactAdded', this.registerContactEventHandlers, this);
this.model.on('change', this.render, this);
this.registerContactEventHandlers();
/**
......@@ -226,9 +230,11 @@ converse.plugins.add('converse-chatview', {
},
toHTML () {
const vcard = _.get(this.model, 'vcard'),
vcard_json = vcard ? vcard.toJSON() : {};
return tpl_user_details_modal(_.extend(
this.model.toJSON(),
this.model.vcard.toJSON(), {
vcard_json, {
'_': _,
'__': __,
'view': this,
......@@ -1380,10 +1386,10 @@ converse.plugins.add('converse-chatview', {
});
_converse.api.listen.on('chatBoxViewsInitialized', () => {
const that = _converse.chatboxviews;
const views = _converse.chatboxviews;
_converse.chatboxes.on('add', item => {
if (!that.get(item.get('id')) && item.get('type') === _converse.PRIVATE_CHAT_TYPE) {
that.add(item.get('id'), new _converse.ChatBoxView({model: item}));
if (!views.get(item.get('id')) && item.get('type') === _converse.PRIVATE_CHAT_TYPE) {
views.add(item.get('id'), new _converse.ChatBoxView({model: item}));
}
});
});
......@@ -1421,7 +1427,7 @@ converse.plugins.add('converse-chatview', {
'get' (jids) {
if (_.isUndefined(jids)) {
_converse.log(
"chats.create: You need to provide at least one JID",
"chatviews.get: You need to provide at least one JID",
Strophe.LogLevel.ERROR
);
return null;
......
......@@ -188,18 +188,18 @@ converse.plugins.add('converse-controlbox', {
const addControlBox = () => _converse.chatboxes.add({'id': 'controlbox'});
_converse.ControlBox = _converse.ChatBox.extend({
defaults: {
defaults () {
return {
'bookmarked': false,
'box_id': 'controlbox',
'chat_state': undefined,
'closed': !_converse.show_controlbox_by_default,
'num_unread': 0,
'time_opened': this.get('time_opened') || moment().valueOf(),
'type': _converse.CONTROLBOX_TYPE,
'url': ''
},
initialize () {
u.safeSave(this, {'time_opened': this.get('time_opened') || moment().valueOf()});
}
}
});
......
......@@ -8,7 +8,7 @@ import "converse-chatview";
import converse from "@converse/headless/converse-core";
import tpl_chatbox from "templates/chatbox.html";
const { _, utils } = converse.env;
const { _, moment, utils } = converse.env;
converse.plugins.add('converse-headline', {
......@@ -52,13 +52,21 @@ converse.plugins.add('converse-headline', {
{ __ } = _converse;
_converse.HeadlinesBox = _converse.ChatBox.extend({
defaults: {
'type': _converse.HEADLINES_TYPE,
defaults () {
return {
'bookmarked': false,
'chat_state': undefined,
'hidden': _.includes(['mobile', 'fullscreen'], _converse.view_mode),
'message_type': 'headline',
'num_unread': 0,
'url': ''
'time_opened': this.get('time_opened') || moment().valueOf(),
'type': _converse.HEADLINES_TYPE
}
},
initialize () {
this.initMessages();
this.set({'box_id': `box-${btoa(this.get('jid'))}`});
}
});
......@@ -110,7 +118,7 @@ converse.plugins.add('converse-headline', {
if (utils.isHeadlineMessage(_converse, message)) {
const from_jid = message.getAttribute('from');
if (_.includes(from_jid, '@') &&
!_converse.api.contacts.get(from_jid) &&
!_converse.roster.get(from_jid) &&
!_converse.allow_non_roster_messaging) {
return;
}
......@@ -142,10 +150,10 @@ converse.plugins.add('converse-headline', {
_converse.api.listen.on('chatBoxViewsInitialized', () => {
const that = _converse.chatboxviews;
const views = _converse.chatboxviews;
_converse.chatboxes.on('add', item => {
if (!that.get(item.get('id')) && item.get('type') === _converse.HEADLINES_TYPE) {
that.add(item.get('id'), new _converse.HeadlinesBoxView({model: item}));
if (!views.get(item.get('id')) && item.get('type') === _converse.HEADLINES_TYPE) {
views.add(item.get('id'), new _converse.HeadlinesBoxView({model: item}));
}
});
});
......
......@@ -108,10 +108,11 @@ converse.plugins.add('converse-muc-views', {
// configuration settings.
_converse.api.settings.update({
'auto_list_rooms': false,
'cache_muc_messages': true,
'locked_muc_domain': false,
'locked_muc_nickname': false,
'muc_disable_moderator_commands': false,
'muc_domain': undefined,
'locked_muc_nickname': false,
'locked_muc_domain': false,
'muc_show_join_leave': true,
'roomconfig_whitelist': [],
'visible_toolbar_buttons': {
......@@ -2130,7 +2131,7 @@ converse.plugins.add('converse-muc-views', {
/* Upon a reconnection event from converse, join again
* all the open groupchats.
*/
_converse.chatboxviews.each(function (view) {
_converse.chatboxviews.each(view => {
if (view.model.get('type') === _converse.CHATROOMS_TYPE) {
view.model.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
view.model.registerHandlers();
......
This diff is collapsed.
......@@ -19,7 +19,7 @@ const MUC_ROLE_WEIGHTS = {
'none': 2,
};
const { Strophe, Backbone, Promise, $iq, $build, $msg, $pres, b64_sha1, sizzle, f, moment, _ } = converse.env;
const { Strophe, Backbone, Promise, $iq, $build, $msg, $pres, sizzle, f, moment, _ } = converse.env;
// Add Strophe Namespaces
Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin");
......@@ -162,7 +162,6 @@ converse.plugins.add('converse-muc', {
*/
settings.type = _converse.CHATROOMS_TYPE;
settings.id = jid;
settings.box_id = b64_sha1(jid)
const chatbox = _converse.chatboxes.getChatBox(jid, settings, true);
chatbox.maybeShow(true);
return chatbox;
......@@ -178,8 +177,7 @@ converse.plugins.add('converse-muc', {
_converse.ChatRoom = _converse.ChatBox.extend({
defaults () {
return _.assign(
_.clone(_converse.ChatBox.prototype.defaults), {
return {
// For group chats, we distinguish between generally unread
// messages and those ones that specifically mention the
// user.
......@@ -191,19 +189,30 @@ converse.plugins.add('converse-muc', {
'num_unread_general': 0,
'affiliation': null,
'bookmarked': false,
'chat_state': undefined,
'connection_status': converse.ROOMSTATUS.DISCONNECTED,
'description': '',
'hidden': _.includes(['mobile', 'fullscreen'], _converse.view_mode),
'message_type': 'groupchat',
'name': '',
'nick': _converse.xmppstatus.get('nickname') || _converse.nickname,
'description': '',
'num_unread': 0,
'roomconfig': {},
'type': _converse.CHATROOMS_TYPE,
'message_type': 'groupchat'
'time_opened': this.get('time_opened') || moment().valueOf(),
'type': _converse.CHATROOMS_TYPE
}
);
},
initialize() {
this.constructor.__super__.initialize.apply(this, arguments);
if (_converse.vcards) {
this.vcard = _converse.vcards.findWhere({'jid': this.get('jid')}) ||
_converse.vcards.create({'jid': this.get('jid')});
}
this.set('box_id', `box-${btoa(this.get('jid'))}`);
this.initMessages();
this.on('change:chat_state', this.sendChatState, this);
this.on('change:connection_status', this.onConnectionStatusChanged, this);
const storage = _converse.config.get('storage');
......@@ -1391,7 +1400,6 @@ converse.plugins.add('converse-muc', {
jid = jid.toLowerCase();
attrs.type = _converse.CHATROOMS_TYPE;
attrs.id = jid;
attrs.box_id = b64_sha1(jid)
return _converse.chatboxes.getChatBox(jid, attrs, create);
};
......
......@@ -880,44 +880,25 @@ converse.plugins.add('converse-roster', {
/********** Event Handlers *************/
function addRelatedContactToChatbox (chatbox, contact) {
if (!_.isUndefined(contact)) {
chatbox.contact = contact;
chatbox.trigger('contactAdded', contact);
}
}
_converse.api.waitUntil('rosterContactsFetched').then(() => {
_converse.roster.on('add', (contact) => {
/* When a new contact is added, check if we already have a
* chatbox open for it, and if so attach it to the chatbox.
*/
const chatbox = _converse.chatboxes.findWhere({'jid': contact.get('jid')});
if (chatbox) {
addRelatedContactToChatbox(chatbox, contact);
}
});
});
function updateUnreadCounter (chatbox) {
const contact = _converse.roster.findWhere({'jid': chatbox.get('jid')});
if (!_.isUndefined(contact)) {
contact.save({'num_unread': chatbox.get('num_unread')});
}
}
_converse.api.listen.on('chatBoxesInitialized', () => {
_converse.chatboxes.on('change:num_unread', updateUnreadCounter)
_converse.chatboxes.on('change:num_unread', updateUnreadCounter);
_converse.chatboxes.on('add', async chatbox => {
await _converse.api.waitUntil('rosterContactsFetched');
addRelatedContactToChatbox(chatbox, _converse.roster.findWhere({'jid': chatbox.get('jid')}));
_converse.chatboxes.on('add', chatbox => {
if (chatbox.get('type') === _converse.PRIVATE_CHAT_TYPE) {
chatbox.setRosterContact(chatbox.get('jid'));
}
});
});
_converse.api.listen.on('beforeTearDown', _converse.unregisterPresenceHandler());
_converse.api.waitUntil('rosterContactsFetched').then(() => {
_converse.roster.on('add', (contact) => {
/* When a new contact is added, check if we already have a
......@@ -925,7 +906,7 @@ converse.plugins.add('converse-roster', {
*/
const chatbox = _converse.chatboxes.findWhere({'jid': contact.get('jid')});
if (chatbox) {
addRelatedContactToChatbox(chatbox, contact);
chatbox.setRosterContact(contact.get('jid'));
}
});
});
......@@ -999,20 +980,20 @@ converse.plugins.add('converse-roster', {
* @method _converse.api.contacts.get
* @params {(string[]|string)} jid|jids The JID or JIDs of
* the contacts to be returned.
* @returns {(RosterContact[]|RosterContact)} [Backbone.Model](http://backbonejs.org/#Model)
* (or an array of them) representing the contact.
* @returns {promise} Promise which resolves with the
* _converse.RosterContact (or an array of them) representing the contact.
*
* @example
* // Fetch a single contact
* _converse.api.listen.on('rosterContactsFetched', function () {
* const contact = _converse.api.contacts.get('buddy@example.com')
* const contact = await _converse.api.contacts.get('buddy@example.com')
* // ...
* });
*
* @example
* // To get multiple contacts, pass in an array of JIDs:
* _converse.api.listen.on('rosterContactsFetched', function () {
* const contacts = _converse.api.contacts.get(
* const contacts = await _converse.api.contacts.get(
* ['buddy1@example.com', 'buddy2@example.com']
* )
* // ...
......@@ -1021,14 +1002,13 @@ converse.plugins.add('converse-roster', {
* @example
* // To return all contacts, simply call ``get`` without any parameters:
* _converse.api.listen.on('rosterContactsFetched', function () {
* const contacts = _converse.api.contacts.get();
* const contacts = await _converse.api.contacts.get();
* // ...
* });
*/
'get' (jids) {
const _getter = function (jid) {
return _converse.roster.get(Strophe.getBareJidFromJid(jid)) || null;
};
async get (jids) {
await _converse.api.waitUntil('rosterContactsFetched');
const _getter = jid => _converse.roster.get(Strophe.getBareJidFromJid(jid));
if (_.isUndefined(jids)) {
jids = _converse.roster.pluck('jid');
} else if (_.isString(jids)) {
......
This diff is collapsed.
......@@ -2,7 +2,9 @@
<div class="chatbox-navback"><i class="fa fa-arrow-left"></i></div>
<div class="chatbox-title">
<div class="row no-gutters">
{[ if (o.type !== o._converse.HEADLINES_TYPE) { ]}
<canvas class="avatar" height="36" width="36"></canvas>
{[ } ]}
<div class="col chat-title" title="{{{o.jid}}}">
{[ if (o.url) { ]}
<a href="{{{o.url}}}" target="_blank" rel="noopener" class="user">
......
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