Commit 879e165a authored by JC Brand's avatar JC Brand

Refactoring

- Move headless one-on-one chat functionality into converse-chat
- Split converse-headline into converse-headlines and converse-headlines-views
- Add api in `_converse.api.chatboxes` for creating chatboxes
- Add `_converse.api.controlbox.get` method
parent 93d56898
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
instances. Still working out a wire protocol for compatibility with other clients. instances. Still working out a wire protocol for compatibility with other clients.
To add custom emojis, edit the `emojis.json` file. To add custom emojis, edit the `emojis.json` file.
- Refactor some presence and status handling code from `converse-core` into `@converse/headless/converse-status`. - Refactor some presence and status handling code from `converse-core` into `@converse/headless/converse-status`.
- New API [\_converse.api.headlines](https://conversejs.org/docs/html/api/-_converse.api.headlines.html#.get)
### Breaking changes ### Breaking changes
...@@ -34,10 +35,12 @@ ...@@ -34,10 +35,12 @@
* `_converse.api.rooms.create` * `_converse.api.rooms.create`
* `_converse.api.roomviews.close` * `_converse.api.roomviews.close`
- `_converse.api.chats.get()` now only returns one-on-one chats, not the control box or headline notifications.
- The `show_only_online_users` setting has been removed. - The `show_only_online_users` setting has been removed.
- The order of certain events have now changed: `statusInitialized` is now triggered after `initialized` and `connected` and `reconnected`. - The order of certain events have now changed: `statusInitialized` is now triggered after `initialized` and `connected` and `reconnected`.
- `_converse.api.alert.show` is now `_converse.api.show` and instead of taking - `_converse.api.alert.show` is now `_converse.api.show` and instead of taking
an integer for the `type`, "info", "warn" or "error" should be passed in. an integer for the `type`, "info", "warn" or "error" should be passed in.
- The `converse-headline` plugin has been split up into `converse-headlines` and `converse-headlines-view`.
## 5.0.4 (2019-10-08) ## 5.0.4 (2019-10-08)
- New config option [allow_message_corrections](https://conversejs.org/docs/html/configuration.html#allow-message-corrections) - New config option [allow_message_corrections](https://conversejs.org/docs/html/configuration.html#allow-message-corrections)
......
...@@ -168,7 +168,7 @@ ...@@ -168,7 +168,7 @@
'name': 'The Play', 'name': 'The Play',
'nick': ' Othello' 'nick': ' Othello'
}); });
await u.waitUntil(() => _converse.api.rooms.get().length); await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
expect(_.isUndefined(_converse.chatboxviews.get(jid))).toBeFalsy(); expect(_.isUndefined(_converse.chatboxviews.get(jid))).toBeFalsy();
// Check that we don't auto-join if muc_respect_autojoin is false // Check that we don't auto-join if muc_respect_autojoin is false
......
This diff is collapsed.
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').t('hello').up() }).c('body').t('hello').up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
_converse.chatboxes.onMessage(msg); _converse.handleMessageStanza(msg);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll(".msgs-indicator").length); await u.waitUntil(() => _converse.rosterview.el.querySelectorAll(".msgs-indicator").length);
spyOn(chatview.model, 'incrementUnreadMsgCounter').and.callThrough(); spyOn(chatview.model, 'incrementUnreadMsgCounter').and.callThrough();
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('1'); expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('1');
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').t('hello again').up() }).c('body').t('hello again').up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
_converse.chatboxes.onMessage(msg); _converse.handleMessageStanza(msg);
await u.waitUntil(() => chatview.model.incrementUnreadMsgCounter.calls.count()); await u.waitUntil(() => chatview.model.incrementUnreadMsgCounter.calls.count());
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('2'); expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('2');
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('2'); expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('2');
......
...@@ -269,7 +269,7 @@ ...@@ -269,7 +269,7 @@
// Test on chat that's not open // Test on chat that's not open
chat = await _converse.api.chats.get(jid); chat = await _converse.api.chats.get(jid);
expect(typeof chat === 'undefined').toBeTruthy(); expect(chat === null).toBeTruthy();
expect(_converse.chatboxes.length).toBe(1); expect(_converse.chatboxes.length).toBe(1);
// Test for one JID // Test for one JID
...@@ -281,7 +281,7 @@ ...@@ -281,7 +281,7 @@
await u.waitUntil(() => u.isVisible(view.el)); await u.waitUntil(() => u.isVisible(view.el));
// Test for multiple JIDs // Test for multiple JIDs
test_utils.openChatBoxFor(_converse, jid2); test_utils.openChatBoxFor(_converse, jid2);
await u.waitUntil(() => _converse.chatboxes.length == 2); await u.waitUntil(() => _converse.chatboxes.length == 3);
const list = await _converse.api.chats.get([jid, jid2]); const list = await _converse.api.chats.get([jid, jid2]);
expect(Array.isArray(list)).toBeTruthy(); expect(Array.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`); expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
......
...@@ -163,7 +163,7 @@ ...@@ -163,7 +163,7 @@
await test_utils.waitForRoster(_converse, 'current'); await test_utils.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
_converse.chatboxes.onMessage($msg({ _converse.handleMessageStanza($msg({
'from': sender_jid, 'from': sender_jid,
'to': _converse.connection.jid, 'to': _converse.connection.jid,
'type': 'chat', 'type': 'chat',
...@@ -177,7 +177,7 @@ ...@@ -177,7 +177,7 @@
let message = chat_content.querySelector('.chat-msg__text'); let message = chat_content.querySelector('.chat-msg__text');
expect(u.hasClass('chat-msg__text--larger', message)).toBe(true); expect(u.hasClass('chat-msg__text--larger', message)).toBe(true);
_converse.chatboxes.onMessage($msg({ _converse.handleMessageStanza($msg({
'from': sender_jid, 'from': sender_jid,
'to': _converse.connection.jid, 'to': _converse.connection.jid,
'type': 'chat', 'type': 'chat',
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
it("will not open nor display non-headline messages", it("will not open nor display non-headline messages",
mock.initConverse( mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
/* XMPP spam message: /* XMPP spam message:
* *
...@@ -36,9 +36,9 @@ ...@@ -36,9 +36,9 @@
.c('nick', {'xmlns': "http://jabber.org/protocol/nick"}).t("-wwdmz").up() .c('nick', {'xmlns': "http://jabber.org/protocol/nick"}).t("-wwdmz").up()
.c('body').t('SORRY FOR THIS ADVERT'); .c('body').t('SORRY FOR THIS ADVERT');
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await u.waitUntil(() => _converse.api.chats.get().length);
expect(u.isHeadlineMessage.called).toBeTruthy(); expect(u.isHeadlineMessage.called).toBeTruthy();
expect(u.isHeadlineMessage.returned(false)).toBeTruthy(); expect(u.isHeadlineMessage.returned(false)).toBeTruthy();
expect(_converse.api.headlines.get().length === 0);
u.isHeadlineMessage.restore(); u.isHeadlineMessage.restore();
done(); done();
})); }));
......
...@@ -205,7 +205,7 @@ ...@@ -205,7 +205,7 @@
describe("An archived message", function () { describe("An archived message", function () {
describe("when recieved", function () { describe("when received", function () {
it("is discarded if it doesn't come from the right sender", it("is discarded if it doesn't come from the right sender",
mock.initConverse( mock.initConverse(
......
This diff is collapsed.
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').t('This message is sent to a minimized chatbox').up() }).c('body').t('This message is sent to a minimized chatbox').up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
_converse.chatboxes.onMessage(msg); _converse.handleMessageStanza(msg);
} }
return u.waitUntil(() => chatview.model.messages.length); return u.waitUntil(() => chatview.model.messages.length);
}).then(() => { }).then(() => {
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((3).toString()); expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((3).toString());
// Chat state notifications don't increment the unread messages counter // Chat state notifications don't increment the unread messages counter
// <composing> state // <composing> state
_converse.chatboxes.onMessage($msg({ _converse.handleMessageStanza($msg({
from: contact_jid, from: contact_jid,
to: _converse.connection.jid, to: _converse.connection.jid,
type: 'chat', type: 'chat',
...@@ -112,7 +112,7 @@ ...@@ -112,7 +112,7 @@
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString()); expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
// <paused> state // <paused> state
_converse.chatboxes.onMessage($msg({ _converse.handleMessageStanza($msg({
from: contact_jid, from: contact_jid,
to: _converse.connection.jid, to: _converse.connection.jid,
type: 'chat', type: 'chat',
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString()); expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
// <gone> state // <gone> state
_converse.chatboxes.onMessage($msg({ _converse.handleMessageStanza($msg({
from: contact_jid, from: contact_jid,
to: _converse.connection.jid, to: _converse.connection.jid,
type: 'chat', type: 'chat',
...@@ -130,7 +130,7 @@ ...@@ -130,7 +130,7 @@
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString()); expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
// <inactive> state // <inactive> state
_converse.chatboxes.onMessage($msg({ _converse.handleMessageStanza($msg({
from: contact_jid, from: contact_jid,
to: _converse.connection.jid, to: _converse.connection.jid,
type: 'chat', type: 'chat',
......
...@@ -89,7 +89,7 @@ ...@@ -89,7 +89,7 @@
// Non-existing room // Non-existing room
muc_jid = 'chillout2@montague.lit'; muc_jid = 'chillout2@montague.lit';
room = await _converse.api.rooms.get(muc_jid); room = await _converse.api.rooms.get(muc_jid);
expect(typeof room === 'undefined').toBeTruthy(); expect(room).toBe(null);
done(); done();
})); }));
......
...@@ -120,7 +120,6 @@ ...@@ -120,7 +120,6 @@
by="room@muc.example.com"/> by="room@muc.example.com"/>
</message>`); </message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await u.waitUntil(() => _converse.api.chats.get().length);
await u.waitUntil(() => view.model.messages.length === 1); await u.waitUntil(() => view.model.messages.length === 1);
await u.waitUntil(() => view.model.findDuplicateFromStanzaID.calls.count() === 1); await u.waitUntil(() => view.model.findDuplicateFromStanzaID.calls.count() === 1);
let result = await view.model.findDuplicateFromStanzaID.calls.all()[0].returnValue; let result = await view.model.findDuplicateFromStanzaID.calls.all()[0].returnValue;
...@@ -572,7 +571,6 @@ ...@@ -572,7 +571,6 @@
const view = _converse.api.chatviews.get(muc_jid); const view = _converse.api.chatviews.get(muc_jid);
view.model.sendMessage('hello world'); view.model.sendMessage('hello world');
await u.waitUntil(() => _converse.api.chats.get().length);
await u.waitUntil(() => view.model.messages.length === 1); await u.waitUntil(() => view.model.messages.length === 1);
const msg = view.model.messages.at(0); const msg = view.model.messages.at(0);
expect(msg.get('stanza_id')).toBeUndefined(); expect(msg.get('stanza_id')).toBeUndefined();
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').t(message).up() }).c('body').t(message).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
await _converse.chatboxes.onMessage(msg); // This will emit 'message' await _converse.handleMessageStanza(msg); // This will emit 'message'
await u.waitUntil(() => _converse.api.chatviews.get(sender_jid)); await u.waitUntil(() => _converse.api.chatviews.get(sender_jid));
expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled(); expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
expect(_converse.showMessageNotification).toHaveBeenCalled(); expect(_converse.showMessageNotification).toHaveBeenCalled();
......
...@@ -303,7 +303,6 @@ ...@@ -303,7 +303,6 @@
spyOn(registerview, 'onRegistrationFields').and.callThrough(); spyOn(registerview, 'onRegistrationFields').and.callThrough();
spyOn(registerview, 'renderRegistrationForm').and.callThrough(); spyOn(registerview, 'renderRegistrationForm').and.callThrough();
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
spyOn(_converse.connection, 'connect').and.callThrough();
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org'; registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
registerview.el.querySelector('input[type=submit]').click(); registerview.el.querySelector('input[type=submit]').click();
......
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
expect(window.confirm).toHaveBeenCalledWith( expect(window.confirm).toHaveBeenCalledWith(
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?'); 'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');
await u.waitUntil(() => !_converse.api.rooms.get().length); await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room"); room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(0); expect(room_els.length).toBe(0);
expect(_converse.chatboxes.length).toBe(1); expect(_converse.chatboxes.length).toBe(1);
......
...@@ -34,8 +34,8 @@ ...@@ -34,8 +34,8 @@
'xmlns': 'urn:xmpp:spoiler:0', 'xmlns': 'urn:xmpp:spoiler:0',
}).t(spoiler_hint) }).t(spoiler_hint)
.tree(); .tree();
await _converse.chatboxes.onMessage(msg); _converse.connection._dataRecv(test_utils.createRequest(msg));
await u.waitUntil(() => _converse.api.chats.get().length === 2); await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
const view = _converse.chatboxviews.get(sender_jid); const view = _converse.chatboxviews.get(sender_jid);
await new Promise(resolve => view.once('messageInserted', resolve)); await new Promise(resolve => view.once('messageInserted', resolve));
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio') await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
...@@ -69,10 +69,10 @@ ...@@ -69,10 +69,10 @@
.c('spoiler', { .c('spoiler', {
'xmlns': 'urn:xmpp:spoiler:0', 'xmlns': 'urn:xmpp:spoiler:0',
}).tree(); }).tree();
await _converse.chatboxes.onMessage(msg); _converse.connection._dataRecv(test_utils.createRequest(msg));
await u.waitUntil(() => _converse.api.chats.get().length === 2); await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
const view = _converse.chatboxviews.get(sender_jid); const view = _converse.chatboxviews.get(sender_jid);
await new Promise(resolve => view.once('messageInserted', resolve)); await u.waitUntil(() => u.isVisible(view.el));
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio') await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, 'Mercutio')).toBeTruthy(); expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, 'Mercutio')).toBeTruthy();
const message_content = view.el.querySelector('.chat-msg__text'); const message_content = view.el.querySelector('.chat-msg__text');
......
...@@ -47,6 +47,7 @@ converse.plugins.add('converse-chatview', { ...@@ -47,6 +47,7 @@ converse.plugins.add('converse-chatview', {
*/ */
dependencies: [ dependencies: [
"converse-chatboxviews", "converse-chatboxviews",
"converse-chat",
"converse-disco", "converse-disco",
"converse-message-view", "converse-message-view",
"converse-modal" "converse-modal"
...@@ -72,17 +73,6 @@ converse.plugins.add('converse-chatview', { ...@@ -72,17 +73,6 @@ converse.plugins.add('converse-chatview', {
}, },
}); });
function onWindowStateChanged (data) {
if (_converse.chatboxviews) {
_converse.chatboxviews.forEach(view => {
if (view.model.get('id') !== 'controlbox') {
view.onWindowStateChanged(data.state);
}
});
}
}
_converse.api.listen.on('windowStateChanged', onWindowStateChanged);
_converse.ChatBoxHeading = _converse.ViewWithAvatar.extend({ _converse.ChatBoxHeading = _converse.ViewWithAvatar.extend({
initialize () { initialize () {
...@@ -92,6 +82,9 @@ converse.plugins.add('converse-chatview', { ...@@ -92,6 +82,9 @@ converse.plugins.add('converse-chatview', {
if (this.model.vcard) { if (this.model.vcard) {
this.listenTo(this.model.vcard, 'change', this.debouncedRender); this.listenTo(this.model.vcard, 'change', this.debouncedRender);
} }
if (this.model.contact) {
this.listenTo(this.model.contact, 'destroy', this.debouncedRender);
}
if (this.model.rosterContactAdded) { if (this.model.rosterContactAdded) {
this.model.rosterContactAdded.then(() => { this.model.rosterContactAdded.then(() => {
this.listenTo(this.model.contact, 'change:nickname', this.debouncedRender); this.listenTo(this.model.contact, 'change:nickname', this.debouncedRender);
...@@ -101,8 +94,8 @@ converse.plugins.add('converse-chatview', { ...@@ -101,8 +94,8 @@ converse.plugins.add('converse-chatview', {
}, },
render () { render () {
const vcard = get(this.model, 'vcard'), const vcard = get(this.model, 'vcard');
vcard_json = vcard ? vcard.toJSON() : {}; const vcard_json = vcard ? vcard.toJSON() : {};
this.el.innerHTML = tpl_chatbox_head( this.el.innerHTML = tpl_chatbox_head(
Object.assign( Object.assign(
vcard_json, vcard_json,
...@@ -409,10 +402,6 @@ converse.plugins.add('converse-chatview', { ...@@ -409,10 +402,6 @@ converse.plugins.add('converse-chatview', {
this.heading = new _converse.ChatBoxHeading({'model': this.model}); this.heading = new _converse.ChatBoxHeading({'model': this.model});
this.heading.render(); this.heading.render();
this.heading.chatview = this; this.heading.chatview = this;
if (this.model.contact !== undefined) {
this.listenTo(this.model.contact, 'destroy', this.heading.render);
}
const flyout = this.el.querySelector('.flyout'); const flyout = this.el.querySelector('.flyout');
flyout.insertBefore(this.heading.el, flyout.querySelector('.chat-body')); flyout.insertBefore(this.heading.el, flyout.querySelector('.chat-body'));
return this; return this;
...@@ -1299,15 +1288,29 @@ converse.plugins.add('converse-chatview', { ...@@ -1299,15 +1288,29 @@ converse.plugins.add('converse-chatview', {
_converse.api.listen.on('chatBoxViewsInitialized', () => { _converse.api.listen.on('chatBoxViewsInitialized', () => {
const views = _converse.chatboxviews; const views = _converse.chatboxviews;
_converse.chatboxes.on('add', item => { _converse.chatboxes.on('add', async item => {
if (!views.get(item.get('id')) && item.get('type') === _converse.PRIVATE_CHAT_TYPE) { if (!views.get(item.get('id')) && item.get('type') === _converse.PRIVATE_CHAT_TYPE) {
await item.initialized;
views.add(item.get('id'), new _converse.ChatBoxView({model: item})); views.add(item.get('id'), new _converse.ChatBoxView({model: item}));
} }
}); });
}); });
// Advertise that we support XEP-0382 Message Spoilers
/************************ BEGIN Event Handlers ************************/
function onWindowStateChanged (data) {
if (_converse.chatboxviews) {
_converse.chatboxviews.forEach(view => {
if (view.model.get('id') !== 'controlbox') {
view.onWindowStateChanged(data.state);
}
});
}
}
_converse.api.listen.on('windowStateChanged', onWindowStateChanged);
_converse.api.listen.on('connected', () => _converse.api.disco.own.features.add(Strophe.NS.SPOILER)); _converse.api.listen.on('connected', () => _converse.api.disco.own.features.add(Strophe.NS.SPOILER));
/************************ END Event Handlers ************************/
/************************ BEGIN API ************************/ /************************ BEGIN API ************************/
Object.assign(_converse.api, { Object.assign(_converse.api, {
......
...@@ -69,7 +69,7 @@ converse.plugins.add('converse-controlbox', { ...@@ -69,7 +69,7 @@ converse.plugins.add('converse-controlbox', {
* *
* NB: These plugins need to have already been loaded via require.js. * NB: These plugins need to have already been loaded via require.js.
*/ */
dependencies: ["converse-modal", "converse-chatboxes", "converse-rosterview", "converse-chatview"], dependencies: ["converse-modal", "converse-chatboxes", "converse-chat", "converse-rosterview", "converse-chatview"],
enabled (_converse) { enabled (_converse) {
return !_converse.singleton; return !_converse.singleton;
...@@ -626,16 +626,25 @@ converse.plugins.add('converse-controlbox', { ...@@ -626,16 +626,25 @@ converse.plugins.add('converse-controlbox', {
* @namespace _converse.api.controlbox * @namespace _converse.api.controlbox
* @memberOf _converse.api * @memberOf _converse.api
*/ */
'controlbox': { controlbox: {
/** /**
* Retrieves the controlbox view. * Opens the controlbox
* * @method _converse.api.controlbox.open
* @returns { Promise<_converse.ControlBox> }
*/
async open () {
await _converse.api.waitUntil('chatBoxesFetched');
const model = await _converse.api.chatboxes.get('controlbox') ||
_converse.api.chatboxes.create('controlbox', {}, _converse.Controlbox);
model.trigger('show');
return model;
},
/**
* Returns the controlbox view.
* @method _converse.api.controlbox.get * @method _converse.api.controlbox.get
* * @returns { Backbone.View } View representing the controlbox
* @example * @example const view = _converse.api.controlbox.get();
* const view = _converse.api.controlbox.get();
*
* @returns {Backbone.View} View representing the controlbox
*/ */
get () { get () {
return _converse.chatboxviews.get('controlbox'); return _converse.chatboxviews.get('controlbox');
......
// Converse.js (A browser based XMPP chat client)
// https://conversejs.org
//
// Copyright (c) 2019, Jan-Carel Brand <jc@opkode.com>
// Licensed under the Mozilla Public License (MPLv2)
/**
* @module converse-headline
*/
import "converse-chatview";
import converse from "@converse/headless/converse-core";
import tpl_chatbox from "templates/chatbox.html";
converse.plugins.add('converse-headlines-view', {
/* Plugin dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
* this plugin.
*
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found. By default it's
* false, which means these plugins are only loaded opportunistically.
*
* NB: These plugins need to have already been loaded via require.js.
*/
dependencies: ["converse-headlines", "converse-chatview"],
initialize () {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const { _converse } = this;
_converse.HeadlinesBoxView = _converse.ChatBoxView.extend({
className: 'chatbox headlines',
events: {
'click .close-chatbox-button': 'close',
'click .toggle-chatbox-button': 'minimize',
'keypress textarea.chat-textarea': 'onKeyDown'
},
initialize () {
this.initDebounced();
this.model.disable_mam = true; // Don't do MAM queries for this box
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
this.listenTo(this.model, 'show', this.show);
this.listenTo(this.model, 'destroy', this.hide);
this.listenTo(this.model, 'change:minimized', this.onMinimizedChanged);
this.render().insertHeading()
this.updateAfterMessagesFetched();
this.insertIntoDOM().hide();
_converse.api.trigger('chatBoxInitialized', this);
},
render () {
this.el.setAttribute('id', this.model.get('box_id'))
this.el.innerHTML = tpl_chatbox(
Object.assign(this.model.toJSON(), {
info_close: '',
label_personal_message: '',
show_send_button: false,
show_toolbar: false,
unread_msgs: ''
}
));
this.content = this.el.querySelector('.chat-content');
return this;
},
// Override to avoid the methods in converse-chatview.js
'renderMessageForm': function renderMessageForm () {},
'afterShown': function afterShown () {}
});
_converse.api.listen.on('chatBoxViewsInitialized', () => {
const views = _converse.chatboxviews;
_converse.chatboxes.on('add', item => {
if (!views.get(item.get('id')) && item.get('type') === _converse.HEADLINES_TYPE) {
views.add(item.get('id'), new _converse.HeadlinesBoxView({model: item}));
}
});
});
}
});
...@@ -112,8 +112,9 @@ converse.plugins.add('converse-minimize', { ...@@ -112,8 +112,9 @@ converse.plugins.add('converse-minimize', {
ChatBoxHeading: { ChatBoxHeading: {
render () { render () {
const { _converse } = this.__super__, const { _converse } = this.__super__;
{ __ } = _converse; const { __ } = _converse;
this.__super__.render.apply(this, arguments); this.__super__.render.apply(this, arguments);
const new_html = tpl_chatbox_minimize({ const new_html = tpl_chatbox_minimize({
'info_minimize': __('Minimize this chat box') 'info_minimize': __('Minimize this chat box')
......
...@@ -91,7 +91,7 @@ converse.plugins.add('converse-roomslist', { ...@@ -91,7 +91,7 @@ converse.plugins.add('converse-roomslist', {
toHTML () { toHTML () {
return tpl_rooms_list({ return tpl_rooms_list({
'rooms': _converse.api.rooms.get(), 'rooms': this.model.filter(m => m.get('type') === _converse.CHATROOMS_TYPE),
'allow_bookmarks': _converse.allow_bookmarks && _converse.bookmarks, 'allow_bookmarks': _converse.allow_bookmarks && _converse.bookmarks,
'collapsed': this.list_model.get('toggle-state') !== _converse.OPENED, 'collapsed': this.list_model.get('toggle-state') !== _converse.OPENED,
'desc_rooms': __('Click to toggle the list of open groupchats'), 'desc_rooms': __('Click to toggle the list of open groupchats'),
......
...@@ -17,10 +17,10 @@ import "converse-controlbox"; // The control box ...@@ -17,10 +17,10 @@ import "converse-controlbox"; // The control box
import "converse-dragresize"; // Allows chat boxes to be resized by dragging them import "converse-dragresize"; // Allows chat boxes to be resized by dragging them
import "converse-emoji-views"; import "converse-emoji-views";
import "converse-fullscreen"; import "converse-fullscreen";
import "converse-headline"; // Support for headline messages
import "converse-mam-views"; import "converse-mam-views";
import "converse-minimize"; // Allows chat boxes to be minimized import "converse-minimize"; // Allows chat boxes to be minimized
import "converse-muc-views"; // Views related to MUC import "converse-muc-views"; // Views related to MUC
import "converse-headlines-view";
import "converse-notification"; // HTML5 Notifications import "converse-notification"; // HTML5 Notifications
import "converse-omemo"; import "converse-omemo";
import "converse-profile"; import "converse-profile";
...@@ -51,6 +51,7 @@ const WHITELISTED_PLUGINS = [ ...@@ -51,6 +51,7 @@ const WHITELISTED_PLUGINS = [
'converse-minimize', 'converse-minimize',
'converse-modal', 'converse-modal',
'converse-muc-views', 'converse-muc-views',
'converse-headlines-view',
'converse-notification', 'converse-notification',
'converse-omemo', 'converse-omemo',
'converse-profile', 'converse-profile',
......
This diff is collapsed.
This diff is collapsed.
...@@ -78,10 +78,12 @@ const CORE_PLUGINS = [ ...@@ -78,10 +78,12 @@ const CORE_PLUGINS = [
'converse-bosh', 'converse-bosh',
'converse-caps', 'converse-caps',
'converse-chatboxes', 'converse-chatboxes',
'converse-chat',
'converse-disco', 'converse-disco',
'converse-emoji', 'converse-emoji',
'converse-mam', 'converse-mam',
'converse-muc', 'converse-muc',
'converse-headlines',
'converse-ping', 'converse-ping',
'converse-pubsub', 'converse-pubsub',
'converse-roster', 'converse-roster',
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
*/ */
import "converse-chatview"; import "converse-chatview";
import converse from "@converse/headless/converse-core"; import converse from "@converse/headless/converse-core";
import tpl_chatbox from "templates/chatbox.html"; import { isString } from "lodash";
const { utils } = converse.env; const { utils } = converse.env;
converse.plugins.add('converse-headline', { converse.plugins.add('converse-headlines', {
/* Plugin dependencies are other plugins which might be /* Plugin dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before * overridden or relied upon, and therefore need to be loaded before
* this plugin. * this plugin.
...@@ -24,7 +24,7 @@ converse.plugins.add('converse-headline', { ...@@ -24,7 +24,7 @@ converse.plugins.add('converse-headline', {
* *
* NB: These plugins need to have already been loaded via require.js. * NB: These plugins need to have already been loaded via require.js.
*/ */
dependencies: ["converse-chatview"], dependencies: ["converse-chat"],
overrides: { overrides: {
// Overrides mentioned here will be picked up by converse.js's // Overrides mentioned here will be picked up by converse.js's
...@@ -71,52 +71,8 @@ converse.plugins.add('converse-headline', { ...@@ -71,52 +71,8 @@ converse.plugins.add('converse-headline', {
}); });
_converse.HeadlinesBoxView = _converse.ChatBoxView.extend({
className: 'chatbox headlines',
events: {
'click .close-chatbox-button': 'close',
'click .toggle-chatbox-button': 'minimize',
'keypress textarea.chat-textarea': 'onKeyDown'
},
initialize () {
this.initDebounced();
this.model.disable_mam = true; // Don't do MAM queries for this box
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
this.listenTo(this.model, 'show', this.show);
this.listenTo(this.model, 'destroy', this.hide);
this.listenTo(this.model, 'change:minimized', this.onMinimizedChanged);
this.render().insertHeading()
this.updateAfterMessagesFetched();
this.insertIntoDOM().hide();
_converse.api.trigger('chatBoxInitialized', this);
},
render () {
this.el.setAttribute('id', this.model.get('box_id'))
this.el.innerHTML = tpl_chatbox(
Object.assign(this.model.toJSON(), {
info_close: '',
label_personal_message: '',
show_send_button: false,
show_toolbar: false,
unread_msgs: ''
}
));
this.content = this.el.querySelector('.chat-content');
return this;
},
// Override to avoid the methods in converse-chatview.js
'renderMessageForm': function renderMessageForm () {},
'afterShown': function afterShown () {}
});
async function onHeadlineMessage (message) { async function onHeadlineMessage (message) {
/* Handler method for all incoming messages of type "headline". */ // Handler method for all incoming messages of type "headline".
if (utils.isHeadlineMessage(_converse, message)) { if (utils.isHeadlineMessage(_converse, message)) {
const from_jid = message.getAttribute('from'); const from_jid = message.getAttribute('from');
if (from_jid.includes('@') && if (from_jid.includes('@') &&
...@@ -140,6 +96,8 @@ converse.plugins.add('converse-headline', { ...@@ -140,6 +96,8 @@ converse.plugins.add('converse-headline', {
} }
} }
/************************ BEGIN Event Handlers ************************/
function registerHeadlineHandler () { function registerHeadlineHandler () {
_converse.connection.addHandler(message => { _converse.connection.addHandler(message => {
onHeadlineMessage(message); onHeadlineMessage(message);
...@@ -148,15 +106,52 @@ converse.plugins.add('converse-headline', { ...@@ -148,15 +106,52 @@ converse.plugins.add('converse-headline', {
} }
_converse.api.listen.on('connected', registerHeadlineHandler); _converse.api.listen.on('connected', registerHeadlineHandler);
_converse.api.listen.on('reconnected', registerHeadlineHandler); _converse.api.listen.on('reconnected', registerHeadlineHandler);
/************************ END Event Handlers ************************/
_converse.api.listen.on('chatBoxViewsInitialized', () => {
const views = _converse.chatboxviews; /************************ BEGIN API ************************/
_converse.chatboxes.on('add', item => { Object.assign(_converse.api, {
if (!views.get(item.get('id')) && item.get('type') === _converse.HEADLINES_TYPE) { /**
views.add(item.get('id'), new _converse.HeadlinesBoxView({model: item})); * The "headlines" namespace, which is used for headline-channels
* which are read-only channels containing messages of type
* "headline".
*
* @namespace _converse.api.headlines
* @memberOf _converse.api
*/
headlines: {
/**
* Retrieves a headline-channel or all headline-channels.
*
* @method _converse.api.headlines.get
* @param {String|String[]} jids - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
* @param {Object} [attrs] - Attributes to be set on the _converse.ChatBox model.
* @param {Boolean} [create=false] - Whether the chat should be created if it's not found.
* @returns { Promise<_converse.HeadlinesBox> }
*/
async get (jids, attrs={}, create=false) {
async function _get (jid) {
let model = await _converse.api.chatboxes.get(jid);
if (!model && create) {
model = await _converse.api.chatboxes.create(jid, attrs, _converse.HeadlinesBox);
} else {
model = (model && model.get('type') === _converse.HEADLINES_TYPE) ? model : null;
if (model && Object.keys(attrs).length) {
model.save(attrs);
}
}
return model;
}
if (jids === undefined) {
const chats = await _converse.api.chatboxes.get();
return chats.filter(c => (c.get('type') === _converse.HEADLINES_TYPE));
} else if (isString(jids)) {
return _get(jids);
}
return Promise.all(jids.map(jid => _get(jid)));
} }
}); }
}); });
/************************ END API ************************/
} }
}); });
...@@ -117,7 +117,7 @@ converse.plugins.add('converse-mam', { ...@@ -117,7 +117,7 @@ converse.plugins.add('converse-mam', {
} }
const message_handler = is_groupchat ? const message_handler = is_groupchat ?
this.onMessage.bind(this) : this.onMessage.bind(this) :
_converse.chatboxes.onMessage.bind(_converse.chatboxes); _converse.handleMessageStanza.bind(_converse.chatboxes);
const query = Object.assign({ const query = Object.assign({
'groupchat': is_groupchat, 'groupchat': is_groupchat,
......
This diff is collapsed.
...@@ -6,15 +6,17 @@ import "./converse-bookmarks"; // XEP-0199 XMPP Ping ...@@ -6,15 +6,17 @@ import "./converse-bookmarks"; // XEP-0199 XMPP Ping
import "./converse-bosh"; // XEP-0206 BOSH import "./converse-bosh"; // XEP-0206 BOSH
import "./converse-caps"; // XEP-0115 Entity Capabilities import "./converse-caps"; // XEP-0115 Entity Capabilities
import "./converse-chatboxes"; // Backbone Collection and Models for chat boxes import "./converse-chatboxes"; // Backbone Collection and Models for chat boxes
import "./converse-chat"; // Support for one-on-one chats
import "./converse-disco"; // XEP-0030 Service discovery import "./converse-disco"; // XEP-0030 Service discovery
import "./converse-mam"; // XEP-0313 Message Archive Management import "./converse-mam"; // XEP-0313 Message Archive Management
import "./converse-muc"; // XEP-0045 Multi-user chat import "./converse-muc"; // XEP-0045 Multi-user chat
import "./converse-headlines"; // Support for headline messages
import "./converse-ping"; // XEP-0199 XMPP Ping import "./converse-ping"; // XEP-0199 XMPP Ping
import "./converse-pubsub"; // XEP-0060 Pubsub import "./converse-pubsub"; // XEP-0060 Pubsub
import "./converse-roster"; // Contacts Roster import "./converse-roster"; // Contacts Roster
import "./converse-rsm"; // XEP-0059 Result Set management import "./converse-rsm"; // XEP-0059 Result Set management
import "./converse-smacks"; // XEP-0198 Stream Management import "./converse-smacks"; // XEP-0198 Stream Management
import "./converse-status"; // XEP-0199 XMPP Ping import "./converse-status"; // XEP-0199 XMPP Ping
import "./converse-vcard"; // XEP-0054 VCard-temp import "./converse-vcard"; // XEP-0054 VCard-temp
/* END: Removable components */ /* END: Removable components */
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
}; };
utils.openControlBox = async function (_converse) { utils.openControlBox = async function (_converse) {
const model = await _converse.api.chats.open('controlbox'); const model = await _converse.api.controlbox.open();
await u.waitUntil(() => model.get('connected')); await u.waitUntil(() => model.get('connected'));
var toggle = document.querySelector(".toggle-controlbox"); var toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
utils.openChatRoomViaModal = async function (_converse, jid, nick='') { utils.openChatRoomViaModal = async function (_converse, jid, nick='') {
// Opens a new chatroom // Opens a new chatroom
const model = await _converse.api.chats.open('controlbox'); const model = await _converse.api.controlbox.open('controlbox');
await u.waitUntil(() => model.get('connected')); await u.waitUntil(() => model.get('connected'));
utils.openControlBox(); utils.openControlBox();
const view = await _converse.chatboxviews.get('controlbox'); const view = await _converse.chatboxviews.get('controlbox');
......
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