Commit f387c947 authored by JC Brand's avatar JC Brand

Allow the full app to be embedded.

- new config option `singleton`.
- new plugin `converse-uniview`
- removed `converse-embedded`.
- various CSS changes, to properly render an embedded full app
- don't re-open cached and non-autojoined chats in singleton mode

The goal here is to extend the `embedded` `view_mode` so that the full app can
also be embedded, not just a single MUC or private chat.

To do this, we'll need to differentiate between multi and singleton chat apps.

* A singleton chat app contains only a single chat.
* A multi-chat app can contain zero or more chats

So we introduce a new config option, `singleton`, which when used with
`view_mode` set to `embedded` will determine whether a single chat or the full
app is embedded.

Similarly, in `overlayed`, `fullscreen` and `mobile` view modes, `singleton`
set to true will allow only one chat within the parameters of that view mode.

We're appropriating the word `singleton` and introducing the concepts of
`uniview` and `multiview` (see a785ca8) to cover what was
previously meant with `singleton`.

updates #1297
parent 2d507c68
...@@ -21,6 +21,9 @@ pip-selfcheck.json ...@@ -21,6 +21,9 @@ pip-selfcheck.json
3rdparty/libsignal-protocol-javascript/ 3rdparty/libsignal-protocol-javascript/
*.map *.map
locale.zip
sounds.zip
analytics.js analytics.js
# virtualenv/python/buildout # virtualenv/python/buildout
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
- Replace `moment` with [DayJS](https://github.com/iamkun/dayjs). - Replace `moment` with [DayJS](https://github.com/iamkun/dayjs).
- New API method [\_converse.api.disco.features.get](https://conversejs.org/docs/html/api/-_converse.api.disco.features.html#.get) - New API method [\_converse.api.disco.features.get](https://conversejs.org/docs/html/api/-_converse.api.disco.features.html#.get)
- New config setting [muc_show_join_leave_status](https://conversejs.org/docs/html/configuration.html#muc-show-join-leave-status) - New config setting [muc_show_join_leave_status](https://conversejs.org/docs/html/configuration.html#muc-show-join-leave-status)
- New config option [singleton](https://conversejs.org/docs/html/configuration.html#singleton).
By setting this option to `false` and `view_mode` to `'embedded'`, it's now possible to
"embed" the full app and not just a single chat. To embed just a single chat,
it's now necessary to explicitly set `singleton` to `true`.
- New event: `chatBoxBlurred`. - New event: `chatBoxBlurred`.
- New event: [chatBoxBlurred](https://conversejs.org/docs/html/api/-_converse.html#event:chatBoxBlurred) - New event: [chatBoxBlurred](https://conversejs.org/docs/html/api/-_converse.html#event:chatBoxBlurred)
- New event: [chatReconnected](https://conversejs.org/docs/html/api/-_converse.html#event:chatReconnected) - New event: [chatReconnected](https://conversejs.org/docs/html/api/-_converse.html#event:chatReconnected)
......
...@@ -90,6 +90,7 @@ ...@@ -90,6 +90,7 @@
notify_all_room_messages: [ notify_all_room_messages: [
'anonymous@conference.nomnom.im', 'anonymous@conference.nomnom.im',
], ],
singleton: true,
locales_url: "../locale/{{{locale}}}/LC_MESSAGES/converse.json", locales_url: "../locale/{{{locale}}}/LC_MESSAGES/converse.json",
view_mode: 'embedded', view_mode: 'embedded',
}); });
......
...@@ -1383,6 +1383,21 @@ show_send_button ...@@ -1383,6 +1383,21 @@ show_send_button
If set to ``true``, a button will be visible which can be clicked to send a message. If set to ``true``, a button will be visible which can be clicked to send a message.
singleton
---------
* Default: ``false``
If set to ``true``, then only one chat (one-on-one or groupchat) will be allowed.
The chat must be specified with the `auto_join_rooms`_ or `auto_join_private_chats`_ options.
This setting is useful together with `view_mode`_ set to ``embedded``, when you
want to embed a chat into the page.
Alternatively you could use it with `view_mode`_ set to ``overlayed`` to create
a single helpdesk-type chat.
sounds_path sounds_path
----------- -----------
......
...@@ -474,12 +474,6 @@ ...@@ -474,12 +474,6 @@
/* ******************* Overlay and embedded styles *************************** */ /* ******************* Overlay and embedded styles *************************** */
#conversejs.converse-embedded {
.chat-textarea {
max-height: var(--fullpage-max-chat-textarea-height);
}
}
#conversejs.converse-embedded, #conversejs.converse-embedded,
#conversejs.converse-overlayed { #conversejs.converse-overlayed {
.chat-head { .chat-head {
...@@ -580,8 +574,31 @@ ...@@ -580,8 +574,31 @@
} }
} }
/* ******************* Fullpage styles *************************** */
#conversejs.converse-embedded.converse-singleton {
.flyout {
border: none !important;
}
.chat-head {
height: var(--fullpage-chat-head-height);
padding: 0.5em;
}
.chatbox {
margin: 0;
@include make-col-ready();
@include media-breakpoint-up(md) {
@include make-col(12);
}
@include media-breakpoint-up(lg) {
@include make-col(12);
}
@include media-breakpoint-up(xl) {
@include make-col(12);
}
}
}
#conversejs.converse-embedded,
#conversejs.converse-fullscreen { #conversejs.converse-fullscreen {
.flyout { .flyout {
border-radius: 0; border-radius: 0;
...@@ -589,13 +606,9 @@ ...@@ -589,13 +606,9 @@
border: var(--flyout-padding) solid var(--chat-head-color); border: var(--flyout-padding) solid var(--chat-head-color);
bottom: 0; bottom: 0;
} }
.chatbox-btn {
font-size: var(--fullpage-chatbox-button-size);
margin: 0 0.3em;
}
.chat-head { .chat-head {
height: var(--fullpage-chat-head-height); height: var(--fullpage-chat-head-height);
font-size: var(--font-size-huge);
padding: 0; padding: 0;
.user-custom-message { .user-custom-message {
font-size: 70%; font-size: 70%;
...@@ -609,18 +622,9 @@ ...@@ -609,18 +622,9 @@
@include make-col(2); @include make-col(2);
} }
} }
.chat-textarea {
max-height: var(--fullpage-max-chat-textarea-height);
}
.emoji-picker {
height: var(--fullpage-emoji-picker-height);
}
.chatbox { .chatbox {
width: 100%;
height: 100%;
margin: 0; margin: 0;
@include make-col-ready(); @include make-col-ready();
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
@include make-col(8); @include make-col(8);
...@@ -632,6 +636,60 @@ ...@@ -632,6 +636,60 @@
@include make-col(10); @include make-col(10);
} }
.box-flyout {
box-shadow: none;
overflow: hidden;
}
}
}
#conversejs.converse-embedded {
.converse-chatboxes {
z-index: 1031; // One more than bootstrap navbar
position: inherit;
flex-wrap: nowrap;
bottom: auto;
height: 100%;
width: 100%;
margin-left: -15px;
}
.chatbox {
.box-flyout {
bottom: 0;
height: 100%;
min-width: auto;
width: 100%;
}
.chat-title {
padding: 0.3em;
font-size: 120%;
}
}
.chat-textarea {
max-height: var(--fullpage-max-chat-textarea-height);
}
}
/* ******************* Fullpage styles *************************** */
#conversejs.converse-fullscreen {
.chatbox-btn {
font-size: var(--fullpage-chatbox-button-size);
margin: 0 0.3em;
}
.chat-head {
font-size: var(--font-size-huge);
}
.chat-textarea {
max-height: var(--fullpage-max-chat-textarea-height);
}
.emoji-picker {
height: var(--fullpage-emoji-picker-height);
}
.chatbox {
.box-flyout { .box-flyout {
background-color: var(--chat-head-color); background-color: var(--chat-head-color);
box-shadow: none; box-shadow: none;
......
...@@ -429,6 +429,7 @@ ...@@ -429,6 +429,7 @@
} }
} }
#conversejs.converse-fullscreen { #conversejs.converse-fullscreen {
.chatroom { .chatroom {
.box-flyout { .box-flyout {
...@@ -462,6 +463,7 @@ ...@@ -462,6 +463,7 @@
} }
} }
#conversejs.converse-embedded,
#conversejs.converse-fullscreen, #conversejs.converse-fullscreen,
#conversejs.converse-mobile { #conversejs.converse-mobile {
...@@ -519,3 +521,42 @@ ...@@ -519,3 +521,42 @@
} }
} }
} }
#conversejs.converse-embedded {
.chatroom {
margin: 0;
width: 100%;
.box-flyout {
.occupants-heading {
font-size: 120%;
}
.chat-content {
.chat-message {
margin: 0.5em;
font-size: 120%;
}
}
.sendXMPPMessage {
.chat-textarea {
padding: 0.5em;
font-size: 110%;
}
}
.chatroom-body {
height: 100%;
.chatroom-form-container {
height: 100%;
position: relative;
}
}
.occupants {
.occupant-list {
padding-left: 0.3em;
li.occupant {
font-size: 120%;
}
}
}
}
}
}
...@@ -435,6 +435,7 @@ ...@@ -435,6 +435,7 @@
} }
} }
#conversejs.converse-embedded,
#conversejs.converse-fullscreen, #conversejs.converse-fullscreen,
#conversejs.converse-mobile { #conversejs.converse-mobile {
#controlbox { #controlbox {
...@@ -545,7 +546,7 @@ ...@@ -545,7 +546,7 @@
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
#conversejs:not(.converse-embedded) { #conversejs {
left: 0; left: 0;
right: 0; right: 0;
padding-left: env(safe-area-inset-left); padding-left: env(safe-area-inset-left);
......
...@@ -120,6 +120,17 @@ body.converse-fullscreen { ...@@ -120,6 +120,17 @@ body.converse-fullscreen {
&.converse-overlayed { &.converse-overlayed {
height: 3em; height: 3em;
} }
&.converse-embedded {
@include box-sizing(border-box);
*, *:before, *:after {
@include box-sizing(border-box);
}
bottom: auto;
height: 100%; // When embedded, it fills the containing element
position: relative;
right: auto;
width: 100%;
}
.brand-heading-container { .brand-heading-container {
text-align: center; text-align: center;
......
#conversejs.converse-embedded {
@include box-sizing(border-box);
*, *:before, *:after {
@include box-sizing(border-box);
}
bottom: auto;
height: 100%; // When embedded, it fills the containing element
position: relative;
right: auto;
width: 100%;
.converse-chatboxes {
z-index: 1031; // One more than bootstrap navbar
position: inherit;
bottom: auto;
height: 100%;
width: 100%;
}
.chatbox {
margin: 0;
height: 100%;
width: 100%;
.flyout.box-flyout {
bottom: 0;
box-shadow: none;
height: 100%;
min-width: auto;
width: 100%;
}
.chat-title {
padding: 0.3em;
font-size: 120%;
}
}
.chatbox-btn {
display: none;
}
.chatroom {
margin: 0;
width: 100%;
.box-flyout {
.occupants-heading {
font-size: 120%;
}
.chat-content {
.chat-message {
margin: 0.5em;
font-size: 120%;
}
}
.sendXMPPMessage {
.chat-textarea {
padding: 0.5em;
font-size: 110%;
}
}
.chatroom-body {
height: 100%;
.chatroom-form-container {
height: 100%;
position: relative;
}
}
.occupants {
.occupant-list {
padding-left: 0.3em;
li.occupant {
font-size: 120%;
}
}
}
}
}
}
...@@ -63,4 +63,3 @@ ...@@ -63,4 +63,3 @@
@import "minimized_chats"; @import "minimized_chats";
@import "bookmarks"; @import "bookmarks";
@import "autocomplete"; @import "autocomplete";
@import "embedded";
...@@ -115,15 +115,11 @@ ...@@ -115,15 +115,11 @@
it("is highlighted if its currently open", mock.initConverse( it("is highlighted if its currently open", mock.initConverse(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ whitelisted_plugins: ['converse-roomslist'], { view_mode: 'fullscreen',
allow_bookmarks: false // Makes testing easier, otherwise we allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
// have to mock stanza traffic.
}, async function (done, _converse) { }, async function (done, _converse) {
spyOn(_converse, 'isUniView').and.callFake(() => true);
let room_els, item; let room_els, item;
test_utils.openControlBox();
await _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); await _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom"); room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
expect(room_els.length).toBe(1); expect(room_els.length).toBe(1);
...@@ -139,6 +135,8 @@ ...@@ -139,6 +135,8 @@
expect(room_els.length).toBe(1); expect(room_els.length).toBe(1);
item = room_els[0]; item = room_els[0];
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit'); expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
const conv_el = document.querySelector('#conversejs');
conv_el.parentElement.removeChild(conv_el);
done(); done();
})); }));
......
...@@ -115,6 +115,9 @@ converse.plugins.add('converse-chatboxviews', { ...@@ -115,6 +115,9 @@ converse.plugins.add('converse-chatboxviews', {
const body = document.querySelector('body'); const body = document.querySelector('body');
body.classList.add(`converse-${_converse.view_mode}`); body.classList.add(`converse-${_converse.view_mode}`);
this.el.classList.add(`converse-${_converse.view_mode}`); this.el.classList.add(`converse-${_converse.view_mode}`);
if (_converse.singleton) {
this.el.classList.add(`converse-singleton`);
}
this.render(); this.render();
}, },
......
...@@ -73,7 +73,7 @@ converse.plugins.add('converse-controlbox', { ...@@ -73,7 +73,7 @@ converse.plugins.add('converse-controlbox', {
dependencies: ["converse-modal", "converse-chatboxes", "converse-rosterview", "converse-chatview"], dependencies: ["converse-modal", "converse-chatboxes", "converse-rosterview", "converse-chatview"],
enabled (_converse) { enabled (_converse) {
return _converse.view_mode !== 'embedded'; return !_converse.singleton;
}, },
overrides: { overrides: {
...@@ -112,7 +112,7 @@ converse.plugins.add('converse-controlbox', { ...@@ -112,7 +112,7 @@ converse.plugins.add('converse-controlbox', {
validate (attrs, options) { validate (attrs, options) {
const { _converse } = this.__super__; const { _converse } = this.__super__;
if (attrs.type === _converse.CONTROLBOX_TYPE) { if (attrs.type === _converse.CONTROLBOX_TYPE) {
if (_converse.view_mode === 'embedded') { if (_converse.view_mode === 'embedded' && _converse.singleton) {
return 'Controlbox not relevant in embedded view mode'; return 'Controlbox not relevant in embedded view mode';
} }
return; return;
......
// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2019, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
import "@converse/headless/converse-muc";
import converse from "@converse/headless/converse-core";
const { Backbone, _ } = converse.env;
converse.plugins.add('converse-embedded', {
enabled (_converse) {
return _converse.view_mode === 'embedded';
},
initialize () {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
this._converse.api.settings.update({
'allow_logout': false, // No point in logging out when we have auto_login as true.
'allow_muc_invitations': false, // Doesn't make sense to allow because only
// roster contacts can be invited
'hide_muc_server': true
});
const { _converse } = this;
if (!Array.isArray(_converse.auto_join_rooms) && !_.isArray(_converse.auto_join_private_chats)) {
throw new Error("converse-embedded: auto_join_rooms must be an Array");
}
if (_converse.auto_join_rooms.length > 1 && _converse.auto_join_private_chats.length > 1) {
throw new Error("converse-embedded: It doesn't make "+
"sense to have the auto_join_rooms setting more then one, "+
"since only one chat room can be open at any time.");
}
}
});
...@@ -14,10 +14,11 @@ import tpl_brand_heading from "templates/inverse_brand_heading.html"; ...@@ -14,10 +14,11 @@ import tpl_brand_heading from "templates/inverse_brand_heading.html";
const { Strophe, _ } = converse.env; const { Strophe, _ } = converse.env;
converse.plugins.add('converse-fullscreen', { converse.plugins.add('converse-fullscreen', {
enabled (_converse) { enabled (_converse) {
return _.includes(['fullscreen', 'embedded'], _converse.view_mode); return _converse.isUniView();
}, },
overrides: { overrides: {
......
...@@ -720,8 +720,8 @@ converse.plugins.add('converse-muc-views', { ...@@ -720,8 +720,8 @@ converse.plugins.add('converse-muc-views', {
*/ */
return tpl_chatroom_head( return tpl_chatroom_head(
Object.assign(this.model.toJSON(), { Object.assign(this.model.toJSON(), {
'_converse': _converse,
'Strophe': Strophe, 'Strophe': Strophe,
'_converse': _converse,
'info_close': __('Close and leave this groupchat'), 'info_close': __('Close and leave this groupchat'),
'info_configure': __('Configure this groupchat'), 'info_configure': __('Configure this groupchat'),
'info_details': __('Show more details about this groupchat'), 'info_details': __('Show more details about this groupchat'),
......
...@@ -7,110 +7,39 @@ ...@@ -7,110 +7,39 @@
/* converse-singleton /* converse-singleton
* ****************** * ******************
* *
* A plugin which ensures that only one chat (private or groupchat) is * A plugin which restricts Converse to only one chat.
* visible at any one time. All other ongoing chats are hidden and kept in the
* background.
*
* This plugin makes sense in mobile or fullscreen chat environments (as
* configured by the `view_mode` setting).
*/ */
import "converse-chatview";
import converse from "@converse/headless/converse-core"; import converse from "@converse/headless/converse-core";
const { _, Strophe } = converse.env; const { _, Strophe } = converse.env;
const u = converse.env.utils; const u = converse.env.utils;
function hideChat (view) {
if (view.model.get('id') === 'controlbox') { return; }
u.safeSave(view.model, {'hidden': true});
view.hide();
}
converse.plugins.add('converse-singleton', { converse.plugins.add('converse-singleton', {
// It's possible however to make optional dependencies non-optional.
// If the setting "strict_plugin_dependencies" is set to true,
// an error will be raised if the plugin is not found.
//
// NB: These plugins need to have already been loaded via require.js.
dependencies: ['converse-chatboxes', 'converse-muc', 'converse-muc-views', 'converse-controlbox', 'converse-rosterview'],
overrides: {
// overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
//
// new functions which don't exist yet can also be added.
ChatBox: {
maybeShow (force) {
// This method must return the chatbox
const { _converse } = this.__super__;
if (!force && _converse.isUniView()) {
if (this.get('id') === 'controlbox') {
return this.trigger('show');
}
const any_chats_visible = _converse.chatboxes
.filter(cb => cb.get('id') != 'controlbox')
.filter(cb => !cb.get('hidden')).length > 0;
if (!any_chats_visible || !this.get('hidden')) {
return this.trigger('show');
}
} else {
return this.__super__.maybeShow.apply(this, arguments);
}
}
},
ChatBoxes: { enabled (_converse) {
createChatBox (jid, attrs) { return _converse.singleton;
/* Make sure new chat boxes are hidden by default. */ },
const { _converse } = this.__super__;
if (_converse.isUniView()) { initialize () {
attrs = attrs || {}; /* The initialize function gets called as soon as the plugin is
attrs.hidden = true; * loaded by converse.js's plugin machinery.
} */
return this.__super__.createChatBox.call(this, jid, attrs); this._converse.api.settings.update({
} 'allow_logout': false, // No point in logging out when we have auto_login as true.
}, 'allow_muc_invitations': false, // Doesn't make sense to allow because only
// roster contacts can be invited
ChatBoxView: { 'hide_muc_server': true
shouldShowOnTextMessage () { });
const { _converse } = this.__super__; const { _converse } = this;
if (_converse.isUniView()) { if (!_.isArray(_converse.auto_join_rooms) && !_.isArray(_converse.auto_join_private_chats)) {
return false; throw new Error("converse-singleton: auto_join_rooms must be an Array");
} else { }
return this.__super__.shouldShowOnTextMessage.apply(this, arguments); if (_converse.auto_join_rooms.length > 1 || _converse.auto_join_private_chats.length > 1) {
} throw new Error("It doesn't make sense to have singleton set to true and " +
}, "auto_join_rooms or auto_join_private_chats set to more then one, " +
"since only one chat room may be open at any time.");
_show (focus) {
/* We only have one chat visible at any one
* time. So before opening a chat, we make sure all other
* chats are hidden.
*/
const { _converse } = this.__super__;
if (_converse.isUniView()) {
_.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
u.safeSave(this.model, {'hidden': false});
}
return this.__super__._show.apply(this, arguments);
}
},
ChatRoomView: {
show (focus) {
const { _converse } = this.__super__;
if (_converse.isUniView()) {
_.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
u.safeSave(this.model, {'hidden': false});
}
return this.__super__.show.apply(this, arguments);
}
} }
} }
}); });
// Converse.js
// http://conversejs.org
//
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
/* converse-uniview
* ****************
*
* A plugin which ensures that only one chat (private or groupchat) is
* visible at any one time. All other ongoing chats are hidden and kept in the
* background.
*
* This plugin makes sense in mobile, embedded or fullscreen chat environments
* (as configured by the `view_mode` setting).
*/
import "converse-chatview";
import converse from "@converse/headless/converse-core";
const { _, Strophe } = converse.env;
const u = converse.env.utils;
function hideChat (view) {
if (view.model.get('id') === 'controlbox') { return; }
u.safeSave(view.model, {'hidden': true});
view.hide();
}
function visibleChats (_converse) {
return _converse.chatboxes
.filter(cb => (cb.get('id') !== 'controlbox' && !cb.get('hidden'))).length > 0;
}
converse.plugins.add('converse-uniview', {
// It's possible however to make optional dependencies non-optional.
// If the setting "strict_plugin_dependencies" is set to true,
// an error will be raised if the plugin is not found.
dependencies: ['converse-chatboxes', 'converse-muc-views', 'converse-controlbox', 'converse-rosterview'],
overrides: {
// overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
//
// new functions which don't exist yet can also be added.
ChatBoxes: {
createChatBox (jid, attrs) {
/* Make sure new chat boxes are hidden by default. */
const { _converse } = this.__super__;
if (_converse.isUniView()) {
attrs = attrs || {};
attrs.hidden = true;
}
return this.__super__.createChatBox.call(this, jid, attrs);
}
},
ChatBox: {
maybeShow () {
const { _converse } = this.__super__;
if (_converse.isUniView() && (!this.get('hidden') || !visibleChats(_converse))) {
return this.trigger("show");
} else {
return this.__super__.maybeShow.apply(this, arguments);
}
}
},
ChatBoxView: {
shouldShowOnTextMessage () {
const { _converse } = this.__super__;
if (_converse.isUniView()) {
return false;
} else {
return this.__super__.shouldShowOnTextMessage.apply(this, arguments);
}
},
_show (focus) {
/* We only have one chat visible at any one
* time. So before opening a chat, we make sure all other
* chats are hidden.
*/
const { _converse } = this.__super__;
if (_converse.isUniView()) {
_.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
u.safeSave(this.model, {'hidden': false});
}
return this.__super__._show.apply(this, arguments);
}
},
ChatRoomView: {
show (focus) {
const { _converse } = this.__super__;
if (_converse.isUniView()) {
_.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
u.safeSave(this.model, {'hidden': false});
}
return this.__super__.show.apply(this, arguments);
}
}
}
});
...@@ -14,7 +14,6 @@ import "converse-bookmark-views"; // Views for XEP-0048 Bookmarks ...@@ -14,7 +14,6 @@ import "converse-bookmark-views"; // Views for XEP-0048 Bookmarks
import "converse-chatview"; // Renders standalone chat boxes for single user chat import "converse-chatview"; // Renders standalone chat boxes for single user chat
import "converse-controlbox"; // The control box 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-embedded";
import "converse-fullscreen"; import "converse-fullscreen";
import "converse-headline"; // Support for headline messages import "converse-headline"; // Support for headline messages
import "converse-mam-views"; import "converse-mam-views";
...@@ -26,6 +25,8 @@ import "converse-push"; // XEP-0357 Push Notifications ...@@ -26,6 +25,8 @@ import "converse-push"; // XEP-0357 Push Notifications
import "converse-register"; // XEP-0077 In-band registration import "converse-register"; // XEP-0077 In-band registration
import "converse-roomslist"; // Show currently open chat rooms import "converse-roomslist"; // Show currently open chat rooms
import "converse-rosterview"; import "converse-rosterview";
import "converse-singleton";
import "converse-uniview";
/* END: Removable components */ /* END: Removable components */
import converse from "@converse/headless/converse-core"; import converse from "@converse/headless/converse-core";
...@@ -37,7 +38,6 @@ const WHITELISTED_PLUGINS = [ ...@@ -37,7 +38,6 @@ const WHITELISTED_PLUGINS = [
'converse-chatview', 'converse-chatview',
'converse-controlbox', 'converse-controlbox',
'converse-dragresize', 'converse-dragresize',
'converse-embedded',
'converse-fullscreen', 'converse-fullscreen',
'converse-headline', 'converse-headline',
'converse-mam-views', 'converse-mam-views',
...@@ -52,7 +52,8 @@ const WHITELISTED_PLUGINS = [ ...@@ -52,7 +52,8 @@ const WHITELISTED_PLUGINS = [
'converse-register', 'converse-register',
'converse-roomslist', 'converse-roomslist',
'converse-rosterview', 'converse-rosterview',
'converse-singleton' 'converse-singleton',
'converse-uniview'
]; ];
const initialize = converse.initialize; const initialize = converse.initialize;
......
...@@ -369,10 +369,13 @@ converse.plugins.add('converse-chatboxes', { ...@@ -369,10 +369,13 @@ converse.plugins.add('converse-chatboxes', {
}, },
validate (attrs, options) { validate (attrs, options) {
const { _converse } = this.__super__;
if (!attrs.jid) { if (!attrs.jid) {
return 'Ignored ChatBox without JID'; return 'Ignored ChatBox without JID';
} }
const auto_join = _converse.auto_join_private_chats.concat(_converse.auto_join_rooms);
if (_converse.singleton && !_.includes(auto_join, attrs.jid)) {
return "Ignored ChatBox that's not being auto joined in singleton mode";
}
}, },
getDisplayName () { getDisplayName () {
...@@ -938,7 +941,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -938,7 +941,8 @@ converse.plugins.add('converse-chatboxes', {
onChatBoxesFetched (collection) { onChatBoxesFetched (collection) {
/* Show chat boxes upon receiving them from sessionStorage */ /* Show chat boxes upon receiving them from sessionStorage */
collection.each(chatbox => chatbox.maybeShow()); collection.filter(c => !c.isValid()).forEach(c => c.destroy());
collection.forEach(c => c.maybeShow());
/** /**
* Triggered when a message stanza is been received and processed. * Triggered when a message stanza is been received and processed.
* @event _converse#message * @event _converse#message
...@@ -957,7 +961,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -957,7 +961,7 @@ converse.plugins.add('converse-chatboxes', {
this.registerMessageHandler(); this.registerMessageHandler();
this.fetch({ this.fetch({
'add': true, 'add': true,
'success': this.onChatBoxesFetched.bind(this) 'success': c => this.onChatBoxesFetched(c)
}); });
}, },
......
...@@ -221,6 +221,7 @@ _converse.default_settings = { ...@@ -221,6 +221,7 @@ _converse.default_settings = {
rid: undefined, rid: undefined,
root: window.document, root: window.document,
sid: undefined, sid: undefined,
singleton: false,
strict_plugin_dependencies: false, strict_plugin_dependencies: false,
trusted: true, trusted: true,
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile' view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
...@@ -337,7 +338,7 @@ function initPlugins() { ...@@ -337,7 +338,7 @@ function initPlugins() {
const whitelist = _converse.core_plugins.concat( const whitelist = _converse.core_plugins.concat(
_converse.whitelisted_plugins); _converse.whitelisted_plugins);
if (_converse.view_mode === 'embedded') { if (_converse.singleton) {
_.forEach([ // eslint-disable-line lodash/prefer-map _.forEach([ // eslint-disable-line lodash/prefer-map
"converse-bookmarks", "converse-bookmarks",
"converse-controlbox", "converse-controlbox",
......
...@@ -13,9 +13,11 @@ ...@@ -13,9 +13,11 @@
<p class="chatroom-description">{{o.description}}</p> <p class="chatroom-description">{{o.description}}</p>
</div> </div>
<div class="chatbox-buttons row no-gutters"> <div class="chatbox-buttons row no-gutters">
<a class="chatbox-btn close-chatbox-button fa fa-sign-out-alt" title="{{{o.info_close}}}"></a> {[ if (!o._converse.singleton) { ]}
<a class="chatbox-btn close-chatbox-button fa fa-sign-out-alt" title="{{{o.info_close}}}"></a>
{[ } ]}
{[ if (o.affiliation == 'owner') { ]} {[ if (o.affiliation == 'owner') { ]}
<a class="chatbox-btn configure-chatroom-button fa fa-wrench" title="{{{o.info_configure}}} "></a> <a class="chatbox-btn configure-chatroom-button fa fa-wrench" title="{{{o.info_configure}}} "></a>
{[ } ]} {[ } ]}
<a class="chatbox-btn show-room-details-modal fa fa-info-circle" title="{{{o.info_details}}}"></a> <a class="chatbox-btn show-room-details-modal fa fa-info-circle" title="{{{o.info_details}}}"></a>
</div> </div>
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