Fix embedded, singleton mode.
It's now necessary to add a `converse-root` element in the DOM where you want Converse to render (previously it was any element with the id `#conversejs`). Also, turned `converse-chats` element into a Lit element and re-render `converse-root` and `converse-chats` when the `view-mode` or `singleton` settings change. This is a step towards being able to change the view mode on the fly and have the entire chat re-render appropriately. Fixes #2647
This commit is contained in:
parent
5ff57258ec
commit
84c6a0039c
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
## 9.0.0 (Unreleased)
|
## 9.0.0 (Unreleased)
|
||||||
|
|
||||||
|
- #2647: Singleton mode doesn't work
|
||||||
|
|
||||||
- Emit a `change` event when a configuration setting changes
|
- Emit a `change` event when a configuration setting changes
|
||||||
- 3 New configuration settings:
|
- 3 New configuration settings:
|
||||||
- [render_media](https://conversejs.org/docs/html/configuration.html#render-media)
|
- [render_media](https://conversejs.org/docs/html/configuration.html#render-media)
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
<p class="intro-text">Embedded MUC chat demo</p>
|
<p class="intro-text">Embedded MUC chat demo</p>
|
||||||
<div class="converse-container">
|
<div class="converse-container">
|
||||||
<div id="conversejs"></div>
|
<converse-root></converse-root>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -828,6 +828,10 @@ Object.assign(converse, {
|
||||||
await initClientConfig(_converse);
|
await initClientConfig(_converse);
|
||||||
await i18n.initialize();
|
await i18n.initialize();
|
||||||
initPlugins(_converse);
|
initPlugins(_converse);
|
||||||
|
|
||||||
|
// Register all custom elements
|
||||||
|
api.elements.register();
|
||||||
|
|
||||||
registerGlobalEventHandlers(_converse);
|
registerGlobalEventHandlers(_converse);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import _converse from '@converse/headless/shared/_converse';
|
import { _converse } from '@converse/headless/core.js';
|
||||||
import assignIn from 'lodash-es/assignIn';
|
import assignIn from 'lodash-es/assignIn';
|
||||||
import isEqual from "lodash-es/isEqual.js";
|
import isEqual from "lodash-es/isEqual.js";
|
||||||
import isObject from 'lodash-es/isObject';
|
import isObject from 'lodash-es/isObject';
|
||||||
|
@ -14,7 +14,6 @@ let app_settings;
|
||||||
let init_settings = {}; // Container for settings passed in via converse.initialize
|
let init_settings = {}; // Container for settings passed in via converse.initialize
|
||||||
let user_settings; // User settings, populated via api.users.settings
|
let user_settings; // User settings, populated via api.users.settings
|
||||||
|
|
||||||
|
|
||||||
export function getAppSettings () {
|
export function getAppSettings () {
|
||||||
return app_settings;
|
return app_settings;
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,13 @@ describe("A chat room", function () {
|
||||||
[{'category': 'pubsub', 'type': 'pep'}],
|
[{'category': 'pubsub', 'type': 'pep'}],
|
||||||
['http://jabber.org/protocol/pubsub#publish-options']
|
['http://jabber.org/protocol/pubsub#publish-options']
|
||||||
);
|
);
|
||||||
await _converse.api.rooms.open(`lounge@montague.lit`);
|
|
||||||
|
const nick = 'romeo';
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
await _converse.api.rooms.open(muc_jid);
|
||||||
|
await mock.getRoomFeatures(_converse, muc_jid);
|
||||||
|
await mock.waitForReservedNick(_converse, muc_jid, nick);
|
||||||
|
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||||
expect(view.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
|
expect(view.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
|
||||||
_converse.bookmarks.create({
|
_converse.bookmarks.create({
|
||||||
|
@ -225,8 +231,12 @@ describe("A chat room", function () {
|
||||||
const { u, Strophe } = converse.env;
|
const { u, Strophe } = converse.env;
|
||||||
await mock.waitForRoster(_converse, 'current', 0);
|
await mock.waitForRoster(_converse, 'current', 0);
|
||||||
await mock.waitUntilBookmarksReturned(_converse);
|
await mock.waitUntilBookmarksReturned(_converse);
|
||||||
|
const nick = 'romeo';
|
||||||
const muc_jid = 'theplay@conference.shakespeare.lit';
|
const muc_jid = 'theplay@conference.shakespeare.lit';
|
||||||
await _converse.api.rooms.open(muc_jid);
|
await _converse.api.rooms.open(muc_jid);
|
||||||
|
await mock.getRoomFeatures(_converse, muc_jid);
|
||||||
|
await mock.waitForReservedNick(_converse, muc_jid, nick);
|
||||||
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark'));
|
await u.waitUntil(() => view.querySelector('.toggle-bookmark'));
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,6 @@ converse.plugins.add('converse-chatboxviews', {
|
||||||
dependencies: ['converse-chatboxes', 'converse-vcard'],
|
dependencies: ['converse-chatboxes', 'converse-vcard'],
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
/* The initialize function gets called as soon as the plugin is
|
|
||||||
* loaded by converse.js's plugin machinery.
|
|
||||||
*/
|
|
||||||
api.elements.register();
|
|
||||||
|
|
||||||
api.promises.add(['chatBoxViewsInitialized']);
|
api.promises.add(['chatBoxViewsInitialized']);
|
||||||
|
|
||||||
// Configuration values for this plugin
|
// Configuration values for this plugin
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
bottom: auto;
|
bottom: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-left: -15px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,31 @@
|
||||||
import tpl_background_logo from '../../templates/background_logo.js';
|
import tpl_background_logo from '../../templates/background_logo.js';
|
||||||
import tpl_chats from './templates/chats.js';
|
import tpl_chats from './templates/chats.js';
|
||||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
import { CustomElement } from 'shared/components/element.js';
|
||||||
import { api, _converse } from '@converse/headless/core';
|
import { api, _converse } from '@converse/headless/core';
|
||||||
|
import { getAppSettings } from '@converse/headless/shared/settings/utils.js';
|
||||||
import { render } from 'lit';
|
import { render } from 'lit';
|
||||||
|
|
||||||
|
|
||||||
class ConverseChats extends ElementView {
|
class ConverseChats extends CustomElement {
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
this.model = _converse.chatboxes;
|
this.model = _converse.chatboxes;
|
||||||
this.listenTo(this.model, 'add', this.render);
|
this.listenTo(this.model, 'add', () => this.requestUpdate());
|
||||||
this.listenTo(this.model, 'change:closed', this.render);
|
this.listenTo(this.model, 'change:closed', () => this.requestUpdate());
|
||||||
this.listenTo(this.model, 'change:hidden', this.render);
|
this.listenTo(this.model, 'change:hidden', () => this.requestUpdate());
|
||||||
this.listenTo(this.model, 'change:jid', this.render);
|
this.listenTo(this.model, 'change:jid', () => this.requestUpdate());
|
||||||
this.listenTo(this.model, 'change:minimized', this.render);
|
this.listenTo(this.model, 'change:minimized', () => this.requestUpdate());
|
||||||
this.listenTo(this.model, 'destroy', this.render);
|
this.listenTo(this.model, 'destroy', () => this.requestUpdate());
|
||||||
|
|
||||||
// Use listenTo instead of api.listen.to so that event handlers
|
// Use listenTo instead of api.listen.to so that event handlers
|
||||||
// automatically get deregistered when the component is dismounted
|
// automatically get deregistered when the component is dismounted
|
||||||
this.listenTo(_converse, 'connected', this.render);
|
this.listenTo(_converse, 'connected', () => this.requestUpdate());
|
||||||
this.listenTo(_converse, 'reconnected', this.render);
|
this.listenTo(_converse, 'reconnected', () => this.requestUpdate());
|
||||||
this.listenTo(_converse, 'disconnected', this.render);
|
this.listenTo(_converse, 'disconnected', () => this.requestUpdate());
|
||||||
|
|
||||||
|
const settings = getAppSettings();
|
||||||
|
this.listenTo(settings, 'change:view_mode', () => this.requestUpdate())
|
||||||
|
this.listenTo(settings, 'change:singleton', () => this.requestUpdate())
|
||||||
|
|
||||||
const bg = document.getElementById('conversejs-bg');
|
const bg = document.getElementById('conversejs-bg');
|
||||||
if (bg && !bg.innerHTML.trim()) {
|
if (bg && !bg.innerHTML.trim()) {
|
||||||
|
@ -28,7 +33,6 @@ class ConverseChats extends ElementView {
|
||||||
}
|
}
|
||||||
const body = document.querySelector('body');
|
const body = document.querySelector('body');
|
||||||
body.classList.add(`converse-${api.settings.get('view_mode')}`);
|
body.classList.add(`converse-${api.settings.get('view_mode')}`);
|
||||||
this.render();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered once the _converse.ChatBoxViews view-colleciton has been initialized
|
* Triggered once the _converse.ChatBoxViews view-colleciton has been initialized
|
||||||
|
@ -38,8 +42,8 @@ class ConverseChats extends ElementView {
|
||||||
api.trigger('chatBoxViewsInitialized');
|
api.trigger('chatBoxViewsInitialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () { // eslint-disable-line class-methods-use-this
|
||||||
render(tpl_chats(), this);
|
return tpl_chats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,28 +101,6 @@
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
&:not(#controlbox) {
|
|
||||||
.box-flyout {
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
max-width: 66.666667%;
|
|
||||||
}
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
max-width: 75%;
|
|
||||||
}
|
|
||||||
@include media-breakpoint-up(xl) {
|
|
||||||
max-width: 83.333333%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
@include make-col(8);
|
|
||||||
}
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
@include make-col(9);
|
|
||||||
}
|
|
||||||
@include media-breakpoint-up(xl) {
|
|
||||||
@include make-col(10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.converse-singleton {
|
&.converse-singleton {
|
||||||
|
@ -134,6 +112,14 @@
|
||||||
}
|
}
|
||||||
.chatbox {
|
.chatbox {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
converse-chats.converse-fullscreen {
|
||||||
|
&.converse-singleton {
|
||||||
|
.chatbox {
|
||||||
@include make-col-ready();
|
@include make-col-ready();
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
@include make-col(12);
|
@include make-col(12);
|
||||||
|
@ -146,6 +132,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:not(.converse-singleton) {
|
||||||
|
.chatbox {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
@include make-col(8);
|
||||||
|
}
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
@include make-col(9);
|
||||||
|
}
|
||||||
|
@include media-breakpoint-up(xl) {
|
||||||
|
@include make-col(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(#controlbox) {
|
||||||
|
.box-flyout {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
max-width: 66.666667%;
|
||||||
|
}
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
max-width: 75%;
|
||||||
|
}
|
||||||
|
@include media-breakpoint-up(xl) {
|
||||||
|
max-width: 83.333333%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converse-chats.converse-embedded {
|
converse-chats.converse-embedded {
|
||||||
|
|
|
@ -9,12 +9,12 @@ const sizzle = converse.env.sizzle;
|
||||||
describe("The Controlbox", function () {
|
describe("The Controlbox", function () {
|
||||||
|
|
||||||
it("can be opened by clicking a DOM element with class 'toggle-controlbox'",
|
it("can be opened by clicking a DOM element with class 'toggle-controlbox'",
|
||||||
mock.initConverse([], {}, function (_converse) {
|
mock.initConverse([], {}, async function (_converse) {
|
||||||
|
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
document.querySelector('.toggle-controlbox').click();
|
document.querySelector('.toggle-controlbox').click();
|
||||||
expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object));
|
expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object));
|
||||||
const el = document.querySelector("#controlbox");
|
const el = await u.waitUntil(() => document.querySelector("#controlbox"));
|
||||||
expect(u.isVisible(el)).toBe(true);
|
expect(u.isVisible(el)).toBe(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
body.converse-fullscreen {
|
body.converse-fullscreen {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: var(--global-background-color);
|
background-color: var(--global-background-color);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,14 +71,15 @@ describe("A Groupchat", function () {
|
||||||
it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
|
it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
|
||||||
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||||
|
|
||||||
await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
|
const muc_jid = 'lounge@conference.shakespeare.lit';
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
const button = await u.waitUntil(() => view.querySelector('.toggle-chatbox-button'));
|
const button = await u.waitUntil(() => view.querySelector('.toggle-chatbox-button'));
|
||||||
button.click();
|
button.click();
|
||||||
|
|
||||||
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
|
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
|
||||||
expect(u.isVisible(view)).toBeFalsy();
|
await u.waitUntil(() => !u.isVisible(view));
|
||||||
expect(view.model.get('minimized')).toBeTruthy();
|
expect(view.model.get('minimized')).toBeTruthy();
|
||||||
const el = await u.waitUntil(() => document.querySelector("converse-minimized-chat a.restore-chat"));
|
const el = await u.waitUntil(() => document.querySelector("converse-minimized-chat a.restore-chat"));
|
||||||
el.click();
|
el.click();
|
||||||
|
@ -107,7 +108,7 @@ describe("A Chatbox", function () {
|
||||||
|
|
||||||
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
|
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
|
||||||
expect(_converse.api.trigger.calls.count(), 2);
|
expect(_converse.api.trigger.calls.count(), 2);
|
||||||
expect(u.isVisible(chatview)).toBeFalsy();
|
await u.waitUntil(() => !u.isVisible(chatview));
|
||||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||||
const restore_el = await u.waitUntil(() => document.querySelector("converse-minimized-chat a.restore-chat"));
|
const restore_el = await u.waitUntil(() => document.querySelector("converse-minimized-chat a.restore-chat"));
|
||||||
restore_el.click();
|
restore_el.click();
|
||||||
|
|
|
@ -100,7 +100,6 @@ describe("Groupchats", function () {
|
||||||
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||||
|
|
||||||
const { api } = _converse;
|
const { api } = _converse;
|
||||||
|
|
||||||
// Mock 'getDiscoInfo', otherwise the room won't be
|
// Mock 'getDiscoInfo', otherwise the room won't be
|
||||||
// displayed as it waits first for the features to be returned
|
// displayed as it waits first for the features to be returned
|
||||||
// (when it's a new room being created).
|
// (when it's a new room being created).
|
||||||
|
@ -116,14 +115,14 @@ describe("Groupchats", function () {
|
||||||
let room = await _converse.api.rooms.open(jid);
|
let room = await _converse.api.rooms.open(jid);
|
||||||
// Test on groupchat that's not yet open
|
// Test on groupchat that's not yet open
|
||||||
expect(room instanceof Model).toBeTruthy();
|
expect(room instanceof Model).toBeTruthy();
|
||||||
chatroomview = _converse.chatboxviews.get(jid);
|
chatroomview = await u.waitUntil(() => _converse.chatboxviews.get(jid));
|
||||||
expect(chatroomview.is_chatroom).toBeTruthy();
|
expect(chatroomview.is_chatroom).toBeTruthy();
|
||||||
await u.waitUntil(() => u.isVisible(chatroomview));
|
await u.waitUntil(() => u.isVisible(chatroomview));
|
||||||
|
|
||||||
// Test again, now that the room exists.
|
// Test again, now that the room exists.
|
||||||
room = await _converse.api.rooms.open(jid);
|
room = await _converse.api.rooms.open(jid);
|
||||||
expect(room instanceof Model).toBeTruthy();
|
expect(room instanceof Model).toBeTruthy();
|
||||||
chatroomview = _converse.chatboxviews.get(jid);
|
chatroomview = await u.waitUntil(() => _converse.chatboxviews.get(jid));
|
||||||
expect(chatroomview.is_chatroom).toBeTruthy();
|
expect(chatroomview.is_chatroom).toBeTruthy();
|
||||||
expect(u.isVisible(chatroomview)).toBeTruthy();
|
expect(u.isVisible(chatroomview)).toBeTruthy();
|
||||||
await chatroomview.close();
|
await chatroomview.close();
|
||||||
|
@ -132,19 +131,19 @@ describe("Groupchats", function () {
|
||||||
jid = 'Leisure@montague.lit';
|
jid = 'Leisure@montague.lit';
|
||||||
room = await _converse.api.rooms.open(jid);
|
room = await _converse.api.rooms.open(jid);
|
||||||
expect(room instanceof Model).toBeTruthy();
|
expect(room instanceof Model).toBeTruthy();
|
||||||
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
|
chatroomview = await u.waitUntil(() => _converse.chatboxviews.get(jid.toLowerCase()));
|
||||||
await u.waitUntil(() => u.isVisible(chatroomview));
|
await u.waitUntil(() => u.isVisible(chatroomview));
|
||||||
|
|
||||||
jid = 'leisure@montague.lit';
|
jid = 'leisure@montague.lit';
|
||||||
room = await _converse.api.rooms.open(jid);
|
room = await _converse.api.rooms.open(jid);
|
||||||
expect(room instanceof Model).toBeTruthy();
|
expect(room instanceof Model).toBeTruthy();
|
||||||
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
|
chatroomview = await u.waitUntil(() => _converse.chatboxviews.get(jid.toLowerCase()));
|
||||||
await u.waitUntil(() => u.isVisible(chatroomview));
|
await u.waitUntil(() => u.isVisible(chatroomview));
|
||||||
|
|
||||||
jid = 'leiSure@montague.lit';
|
jid = 'leiSure@montague.lit';
|
||||||
room = await _converse.api.rooms.open(jid);
|
room = await _converse.api.rooms.open(jid);
|
||||||
expect(room instanceof Model).toBeTruthy();
|
expect(room instanceof Model).toBeTruthy();
|
||||||
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
|
chatroomview = await u.waitUntil(() => _converse.chatboxviews.get(jid.toLowerCase()));
|
||||||
await u.waitUntil(() => u.isVisible(chatroomview));
|
await u.waitUntil(() => u.isVisible(chatroomview));
|
||||||
chatroomview.close();
|
chatroomview.close();
|
||||||
|
|
||||||
|
@ -168,7 +167,6 @@ describe("Groupchats", function () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(room instanceof Model).toBeTruthy();
|
expect(room instanceof Model).toBeTruthy();
|
||||||
chatroomview = _converse.chatboxviews.get('room@conference.example.org');
|
|
||||||
|
|
||||||
// We pretend this is a new room, so no disco info is returned.
|
// We pretend this is a new room, so no disco info is returned.
|
||||||
const features_stanza = $iq({
|
const features_stanza = $iq({
|
||||||
|
@ -247,6 +245,7 @@ describe("Groupchats", function () {
|
||||||
</query>
|
</query>
|
||||||
</iq>`);
|
</iq>`);
|
||||||
|
|
||||||
|
chatroomview = _converse.chatboxviews.get('room@conference.example.org');
|
||||||
spyOn(chatroomview.model, 'sendConfiguration').and.callThrough();
|
spyOn(chatroomview.model, 'sendConfiguration').and.callThrough();
|
||||||
_converse.connection._dataRecv(mock.createRequest(node));
|
_converse.connection._dataRecv(mock.createRequest(node));
|
||||||
await u.waitUntil(() => chatroomview.model.sendConfiguration.calls.count() === 1);
|
await u.waitUntil(() => chatroomview.model.sendConfiguration.calls.count() === 1);
|
||||||
|
|
|
@ -1214,7 +1214,7 @@ describe("Groupchats", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
await _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
await _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||||
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
const view = await u.waitUntil(() => _converse.chatboxviews.get('coven@chat.shakespeare.lit'));
|
||||||
await u.waitUntil(() => u.isVisible(view));
|
await u.waitUntil(() => u.isVisible(view));
|
||||||
// We pretend this is a new room, so no disco info is returned.
|
// We pretend this is a new room, so no disco info is returned.
|
||||||
const features_stanza = $iq({
|
const features_stanza = $iq({
|
||||||
|
@ -2275,7 +2275,7 @@ describe("Groupchats", function () {
|
||||||
* </presence>
|
* </presence>
|
||||||
*/
|
*/
|
||||||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||||
var presence = $pres().attrs({
|
const presence = $pres().attrs({
|
||||||
from:'lounge@montague.lit/romeo',
|
from:'lounge@montague.lit/romeo',
|
||||||
to:'romeo@montague.lit/pda',
|
to:'romeo@montague.lit/pda',
|
||||||
type:'unavailable'
|
type:'unavailable'
|
||||||
|
@ -2335,16 +2335,16 @@ describe("Groupchats", function () {
|
||||||
it("can be closed again by clicking a DOM element with class 'close-chatbox-button'",
|
it("can be closed again by clicking a DOM element with class 'close-chatbox-button'",
|
||||||
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||||
|
|
||||||
await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
|
const model = await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
spyOn(model, 'close').and.callThrough();
|
||||||
spyOn(view.model, 'close').and.callThrough();
|
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
spyOn(view.model, 'leave');
|
spyOn(model, 'leave');
|
||||||
spyOn(_converse.api, 'confirm').and.callFake(() => Promise.resolve(true));
|
spyOn(_converse.api, 'confirm').and.callFake(() => Promise.resolve(true));
|
||||||
|
const view = await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit'));
|
||||||
const button = await u.waitUntil(() => view.querySelector('.close-chatbox-button'));
|
const button = await u.waitUntil(() => view.querySelector('.close-chatbox-button'));
|
||||||
button.click();
|
button.click();
|
||||||
await u.waitUntil(() => view.model.close.calls.count());
|
await u.waitUntil(() => model.close.calls.count());
|
||||||
expect(view.model.leave).toHaveBeenCalled();
|
expect(model.leave).toHaveBeenCalled();
|
||||||
await u.waitUntil(() => _converse.api.trigger.calls.count());
|
await u.waitUntil(() => _converse.api.trigger.calls.count());
|
||||||
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
|
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
|
||||||
}));
|
}));
|
||||||
|
@ -3980,7 +3980,7 @@ describe("Groupchats", function () {
|
||||||
var new_list = [];
|
var new_list = [];
|
||||||
var old_list = [];
|
var old_list = [];
|
||||||
const muc_utils = converse.env.muc_utils;
|
const muc_utils = converse.env.muc_utils;
|
||||||
var delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
|
let delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
|
||||||
expect(delta.length).toBe(0);
|
expect(delta.length).toBe(0);
|
||||||
|
|
||||||
new_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'member'}];
|
new_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'member'}];
|
||||||
|
@ -4272,7 +4272,7 @@ describe("Groupchats", function () {
|
||||||
rooms[4].querySelector('.open-room').click();
|
rooms[4].querySelector('.open-room').click();
|
||||||
await u.waitUntil(() => _converse.chatboxes.length > 1);
|
await u.waitUntil(() => _converse.chatboxes.length > 1);
|
||||||
expect(sizzle('.chatroom', _converse.el).filter(u.isVisible).length).toBe(1); // There should now be an open chatroom
|
expect(sizzle('.chatroom', _converse.el).filter(u.isVisible).length).toBe(1); // There should now be an open chatroom
|
||||||
var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit');
|
const view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit');
|
||||||
expect(view.querySelector('.chatbox-title__text').textContent.trim()).toBe("Macbeth's Castle");
|
expect(view.querySelector('.chatbox-title__text').textContent.trim()).toBe("Macbeth's Castle");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -4577,7 +4577,7 @@ describe("Groupchats", function () {
|
||||||
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
|
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
|
||||||
|
|
||||||
// <composing> state
|
// <composing> state
|
||||||
var msg = $msg({
|
let msg = $msg({
|
||||||
from: muc_jid+'/newguy',
|
from: muc_jid+'/newguy',
|
||||||
id: u.getUniqueId(),
|
id: u.getUniqueId(),
|
||||||
to: 'romeo@montague.lit',
|
to: 'romeo@montague.lit',
|
||||||
|
|
|
@ -201,7 +201,6 @@ describe("A groupchat shown in the groupchats list", function () {
|
||||||
await mock.waitForRoster(_converse, 'current', 0);
|
await mock.waitForRoster(_converse, 'current', 0);
|
||||||
await mock.openControlBox(_converse);
|
await mock.openControlBox(_converse);
|
||||||
await _converse.api.rooms.open(room_jid, {'nick': 'some1'});
|
await _converse.api.rooms.open(room_jid, {'nick': 'some1'});
|
||||||
const view = _converse.chatboxviews.get(room_jid);
|
|
||||||
|
|
||||||
const selector = `iq[to="${room_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`;
|
const selector = `iq[to="${room_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`;
|
||||||
const features_query = await u.waitUntil(() => IQ_stanzas.filter(iq => iq.querySelector(selector)).pop());
|
const features_query = await u.waitUntil(() => IQ_stanzas.filter(iq => iq.querySelector(selector)).pop());
|
||||||
|
@ -233,6 +232,8 @@ describe("A groupchat shown in the groupchats list", function () {
|
||||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||||
.c('value').t(0);
|
.c('value').t(0);
|
||||||
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
||||||
|
|
||||||
|
const view = _converse.chatboxviews.get(room_jid);
|
||||||
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||||
let presence = $pres({
|
let presence = $pres({
|
||||||
to: _converse.connection.jid,
|
to: _converse.connection.jid,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import './root.js';
|
import ConverseRoot from './root.js';
|
||||||
import { api, converse } from '@converse/headless/core';
|
import { api, converse } from '@converse/headless/core';
|
||||||
import { ensureElement } from './utils.js';
|
import { ensureElement } from './utils.js';
|
||||||
|
|
||||||
|
@ -8,5 +8,10 @@ converse.plugins.add('converse-rootview', {
|
||||||
initialize () {
|
initialize () {
|
||||||
api.settings.extend({ 'auto_insert': true });
|
api.settings.extend({ 'auto_insert': true });
|
||||||
api.listen.on('chatBoxesInitialized', ensureElement);
|
api.listen.on('chatBoxesInitialized', ensureElement);
|
||||||
|
|
||||||
|
// Only define the element now, otherwise it it's already in the DOM
|
||||||
|
// before `converse.initialized` has been called it will render too
|
||||||
|
// early.
|
||||||
|
api.elements.define('converse-root', ConverseRoot);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import tpl_root from "./templates/root.js";
|
import tpl_root from "./templates/root.js";
|
||||||
import { api } from '@converse/headless/core';
|
import { api } from '@converse/headless/core';
|
||||||
import { CustomElement } from 'shared/components/element.js';
|
import { CustomElement } from 'shared/components/element.js';
|
||||||
|
import { getAppSettings } from '@converse/headless/shared/settings/utils.js';
|
||||||
|
|
||||||
|
import './styles/root.scss';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,19 +13,25 @@ import { CustomElement } from 'shared/components/element.js';
|
||||||
* It can be inserted into the DOM before or after Converse has loaded or been
|
* It can be inserted into the DOM before or after Converse has loaded or been
|
||||||
* initialized.
|
* initialized.
|
||||||
*/
|
*/
|
||||||
class ConverseRoot extends CustomElement {
|
export default class ConverseRoot extends CustomElement {
|
||||||
|
|
||||||
render () { // eslint-disable-line class-methods-use-this
|
render () { // eslint-disable-line class-methods-use-this
|
||||||
return tpl_root();
|
return tpl_root();
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback () {
|
initialize () {
|
||||||
super.connectedCallback();
|
this.setAttribute('id', 'conversejs');
|
||||||
|
this.setClasses();
|
||||||
|
const settings = getAppSettings();
|
||||||
|
this.listenTo(settings, 'change:view_mode', () => this.setClasses())
|
||||||
|
this.listenTo(settings, 'change:singleton', () => this.setClasses())
|
||||||
|
}
|
||||||
|
|
||||||
|
setClasses () {
|
||||||
|
this.className = "";
|
||||||
this.classList.add('conversejs');
|
this.classList.add('conversejs');
|
||||||
this.classList.add(`converse-${api.settings.get('view_mode')}`);
|
this.classList.add(`converse-${api.settings.get('view_mode')}`);
|
||||||
this.classList.add(`theme-${api.settings.get('theme')}`);
|
this.classList.add(`theme-${api.settings.get('theme')}`);
|
||||||
this.setAttribute('id', 'conversejs');
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('converse-root', ConverseRoot);
|
|
||||||
|
|
16
src/plugins/rootview/styles/root.scss
Normal file
16
src/plugins/rootview/styles/root.scss
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
converse-root.converse-js {
|
||||||
|
&.converse-fullpage,
|
||||||
|
&.converse-overlayed,
|
||||||
|
&.converse-mobile {
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
padding-left: env(safe-area-inset-left);
|
||||||
|
padding-right: env(safe-area-inset-right);
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1031; // One more than bootstrap navbar
|
||||||
|
}
|
||||||
|
|
||||||
|
&.converse-embedded {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,10 @@ import { api } from '@converse/headless/core';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
let extra_classes = api.settings.get('singleton') ? 'converse-singleton' : '';
|
const extra_classes = api.settings.get('singleton') ? ['converse-singleton'] : [];
|
||||||
extra_classes += `converse-${api.settings.get('view_mode')}`;
|
extra_classes.push(`converse-${api.settings.get('view_mode')}`);
|
||||||
return html`
|
return html`
|
||||||
<converse-chats class="converse-chatboxes row no-gutters ${extra_classes}"></converse-chats>
|
<converse-chats class="converse-chatboxes row no-gutters ${extra_classes.join(' ')}"></converse-chats>
|
||||||
<div id="converse-modals" class="modals"></div>
|
<div id="converse-modals" class="modals"></div>
|
||||||
<converse-fontawesome></converse-fontawesome>
|
<converse-fontawesome></converse-fontawesome>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -6,7 +6,7 @@ export function ensureElement () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const root = api.settings.get('root');
|
const root = api.settings.get('root');
|
||||||
if (!root.querySelector('converse-root#conversejs')) {
|
if (!root.querySelector('converse-root')) {
|
||||||
const el = document.createElement('converse-root');
|
const el = document.createElement('converse-root');
|
||||||
const body = root.querySelector('body');
|
const body = root.querySelector('body');
|
||||||
if (body) {
|
if (body) {
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
.conversejs {
|
.conversejs {
|
||||||
bottom: 0;
|
|
||||||
height: 100%;
|
|
||||||
position: fixed;
|
|
||||||
padding-left: env(safe-area-inset-left);
|
|
||||||
padding-right: env(safe-area-inset-right);
|
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-family: var(--normal-font);
|
font-family: var(--normal-font);
|
||||||
font-size: var(--font-size);
|
font-size: var(--font-size);
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
z-index: 1031; // One more than bootstrap navbar
|
|
||||||
|
|
||||||
.flyout {
|
.flyout {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user