Render the MUC view component declaratively
This commit is contained in:
parent
851bfc61e0
commit
d8daedea0d
@ -1,3 +1,15 @@
|
|||||||
|
converse-muc-config-form {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
converse-muc-disconnected,
|
||||||
|
converse-muc-destroyed {
|
||||||
|
padding: 2em;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#conversejs.converse-embedded,
|
#conversejs.converse-embedded,
|
||||||
#conversejs {
|
#conversejs {
|
||||||
.badge--muc {
|
.badge--muc {
|
||||||
@ -324,7 +336,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.chatroom-form-container {
|
.muc-form-container {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border: 0;
|
border: 0;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
@ -376,7 +388,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
height: 16em;
|
height: 16em;
|
||||||
|
|
||||||
.chatroom-form-container {
|
.muc-form-container {
|
||||||
.chatroom-form {
|
.chatroom-form {
|
||||||
padding-top: 2em;
|
padding-top: 2em;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
@ -528,7 +540,7 @@
|
|||||||
}
|
}
|
||||||
.chatroom-body {
|
.chatroom-body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.chatroom-form-container {
|
.muc-form-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,10 @@
|
|||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.converse-form--spinner {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&.converse-centered-form {
|
&.converse-centered-form {
|
||||||
min-height: 66%;
|
min-height: 66%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -27,21 +27,20 @@ describe("A chat room", function () {
|
|||||||
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
|
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
|
||||||
await mock.returnMemberLists(_converse, muc_jid, [], ['member', 'admin', 'owner']);
|
await mock.returnMemberLists(_converse, muc_jid, [], ['member', 'admin', 'owner']);
|
||||||
|
|
||||||
spyOn(view, 'renderBookmarkForm').and.callThrough();
|
|
||||||
spyOn(view, 'closeForm').and.callThrough();
|
|
||||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
|
await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
|
||||||
const toggle = view.querySelector('.toggle-bookmark');
|
const toggle = view.querySelector('.toggle-bookmark');
|
||||||
expect(toggle.title).toBe('Bookmark this groupchat');
|
expect(toggle.title).toBe('Bookmark this groupchat');
|
||||||
toggle.click();
|
toggle.click();
|
||||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
|
||||||
|
|
||||||
view.querySelector('.button-cancel').click();
|
const cancel_button = await u.waitUntil(() => view.querySelector('.button-cancel'));
|
||||||
expect(view.closeForm).toHaveBeenCalled();
|
expect(view.model.session.get('view')).toBe('bookmark-form');
|
||||||
|
cancel_button.click();
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.model.session.get('view') === null);
|
||||||
expect(u.hasClass('on-button', toggle), false);
|
expect(u.hasClass('on-button', toggle), false);
|
||||||
expect(toggle.title).toBe('Bookmark this groupchat');
|
expect(toggle.title).toBe('Bookmark this groupchat');
|
||||||
|
|
||||||
toggle.click();
|
toggle.click();
|
||||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
|
||||||
|
|
||||||
/* Client uploads data:
|
/* Client uploads data:
|
||||||
* --------------------
|
* --------------------
|
||||||
@ -75,13 +74,13 @@ describe("A chat room", function () {
|
|||||||
* </iq>
|
* </iq>
|
||||||
*/
|
*/
|
||||||
expect(view.model.get('bookmarked')).toBeFalsy();
|
expect(view.model.get('bookmarked')).toBeFalsy();
|
||||||
const form = view.querySelector('.chatroom-form');
|
const form = await u.waitUntil(() => view.querySelector('.chatroom-form'));
|
||||||
form.querySelector('input[name="name"]').value = 'Play's the Thing';
|
form.querySelector('input[name="name"]').value = 'Play's the Thing';
|
||||||
form.querySelector('input[name="autojoin"]').checked = 'checked';
|
form.querySelector('input[name="autojoin"]').checked = 'checked';
|
||||||
form.querySelector('input[name="nick"]').value = 'JC';
|
form.querySelector('input[name="nick"]').value = 'JC';
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
view.querySelector('.muc-bookmark-form .btn-primary').click();
|
view.querySelector('converse-muc-bookmark-form .btn-primary').click();
|
||||||
|
|
||||||
const sent_stanza = await u.waitUntil(
|
const sent_stanza = await u.waitUntil(
|
||||||
() => IQ_stanzas.filter(s => sizzle('iq publish[node="storage:bookmarks"]', s).length).pop());
|
() => IQ_stanzas.filter(s => sizzle('iq publish[node="storage:bookmarks"]', s).length).pop());
|
||||||
|
@ -314,19 +314,19 @@ describe("A sent groupchat message", function () {
|
|||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
spyOn(_converse.connection, 'send');
|
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
bottom_panel.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
const msg = _converse.connection.send.calls.all()[0].args[0];
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
expect(msg.toLocaleString())
|
const msg = await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop());
|
||||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
|
expect(Strophe.serialize(msg))
|
||||||
|
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.getAttribute("id")}" `+
|
||||||
`to="lounge@montague.lit" type="groupchat" `+
|
`to="lounge@montague.lit" type="groupchat" `+
|
||||||
`xmlns="jabber:client">`+
|
`xmlns="jabber:client">`+
|
||||||
`<body>hello Link Mauve</body>`+
|
`<body>hello Link Mauve</body>`+
|
||||||
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
|
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
|
||||||
`<reference begin="6" end="16" type="mention" uri="xmpp:lounge@montague.lit/Link%20Mauve" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="6" end="16" type="mention" uri="xmpp:lounge@montague.lit/Link%20Mauve" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
`<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||||
`</message>`);
|
`</message>`);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
@ -374,7 +374,6 @@ describe("A sent groupchat message", function () {
|
|||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
spyOn(_converse.connection, 'send');
|
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
bottom_panel.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
@ -385,9 +384,10 @@ describe("A sent groupchat message", function () {
|
|||||||
'hello <span class="mention">z3r0</span> <span class="mention">gibson</span> <span class="mention">mr.robot</span>, how are you?'
|
'hello <span class="mention">z3r0</span> <span class="mention">gibson</span> <span class="mention">mr.robot</span>, how are you?'
|
||||||
);
|
);
|
||||||
|
|
||||||
const msg = _converse.connection.send.calls.all()[0].args[0];
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
expect(msg.toLocaleString())
|
const msg = await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop());
|
||||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
|
expect(Strophe.serialize(msg))
|
||||||
|
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.getAttribute("id")}" `+
|
||||||
`to="lounge@montague.lit" type="groupchat" `+
|
`to="lounge@montague.lit" type="groupchat" `+
|
||||||
`xmlns="jabber:client">`+
|
`xmlns="jabber:client">`+
|
||||||
`<body>hello z3r0 gibson mr.robot, how are you?</body>`+
|
`<body>hello z3r0 gibson mr.robot, how are you?</body>`+
|
||||||
@ -395,7 +395,7 @@ describe("A sent groupchat message", function () {
|
|||||||
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<reference begin="18" end="26" type="mention" uri="xmpp:mr.robot@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="18" end="26" type="mention" uri="xmpp:mr.robot@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
`<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||||
`</message>`);
|
`</message>`);
|
||||||
|
|
||||||
const action = await u.waitUntil(() => view.querySelector('.chat-msg .chat-msg__action'));
|
const action = await u.waitUntil(() => view.querySelector('.chat-msg .chat-msg__action'));
|
||||||
@ -406,16 +406,15 @@ describe("A sent groupchat message", function () {
|
|||||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||||
await u.waitUntil(() => _converse.connection.send.calls.count() === 1);
|
|
||||||
|
|
||||||
textarea.value = 'hello @z3r0 @gibson @sw0rdf1sh, how are you?';
|
textarea.value = 'hello @z3r0 @gibson @sw0rdf1sh, how are you?';
|
||||||
bottom_panel.onKeyDown(enter_event);
|
bottom_panel.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||||
'hello z3r0 gibson sw0rdf1sh, how are you?', 500);
|
'hello z3r0 gibson sw0rdf1sh, how are you?', 500);
|
||||||
|
|
||||||
const correction = _converse.connection.send.calls.all()[1].args[0];
|
const correction = sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop();
|
||||||
expect(correction.toLocaleString())
|
expect(Strophe.serialize(correction))
|
||||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${correction.nodeTree.getAttribute("id")}" `+
|
.toBe(`<message from="romeo@montague.lit/orchard" id="${correction.getAttribute("id")}" `+
|
||||||
`to="lounge@montague.lit" type="groupchat" `+
|
`to="lounge@montague.lit" type="groupchat" `+
|
||||||
`xmlns="jabber:client">`+
|
`xmlns="jabber:client">`+
|
||||||
`<body>hello z3r0 gibson sw0rdf1sh, how are you?</body>`+
|
`<body>hello z3r0 gibson sw0rdf1sh, how are you?</body>`+
|
||||||
@ -423,8 +422,8 @@ describe("A sent groupchat message", function () {
|
|||||||
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<reference begin="18" end="27" type="mention" uri="xmpp:sw0rdf1sh@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
`<reference begin="18" end="27" type="mention" uri="xmpp:sw0rdf1sh@montague.lit" xmlns="urn:xmpp:reference:0"/>`+
|
||||||
`<replace id="${msg.nodeTree.getAttribute("id")}" xmlns="urn:xmpp:message-correct:0"/>`+
|
`<replace id="${msg.getAttribute("id")}" xmlns="urn:xmpp:message-correct:0"/>`+
|
||||||
`<origin-id id="${correction.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
`<origin-id id="${correction.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||||
`</message>`);
|
`</message>`);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
@ -1281,6 +1281,9 @@ describe("A Chat Message", function () {
|
|||||||
await mock.openChatBoxFor(_converse, contact_jid);
|
await mock.openChatBoxFor(_converse, contact_jid);
|
||||||
|
|
||||||
const messages = _converse.connection.sent_stanzas.filter(s => s.nodeName === 'message');
|
const messages = _converse.connection.sent_stanzas.filter(s => s.nodeName === 'message');
|
||||||
|
if (messages.length > 1) {
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
expect(messages.length).toBe(1);
|
expect(messages.length).toBe(1);
|
||||||
expect(Strophe.serialize(messages[0])).toBe(
|
expect(Strophe.serialize(messages[0])).toBe(
|
||||||
`<message id="${messages[0].getAttribute('id')}" to="tybalt@montague.lit" type="chat" xmlns="jabber:client">`+
|
`<message id="${messages[0].getAttribute('id')}" to="tybalt@montague.lit" type="chat" xmlns="jabber:client">`+
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*global mock, converse */
|
/*global mock, converse */
|
||||||
|
|
||||||
const Model = converse.env.Model;
|
const Model = converse.env.Model;
|
||||||
const { sizzle, u } = converse.env;
|
const { $pres, $iq, Strophe, sizzle, u } = converse.env;
|
||||||
|
|
||||||
describe("Groupchats", function () {
|
describe("Groupchats", function () {
|
||||||
|
|
||||||
|
140
spec/muc.js
140
spec/muc.js
@ -147,7 +147,6 @@ describe("Groupchats", function () {
|
|||||||
return done();
|
return done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it("maintains its state across reloads",
|
it("maintains its state across reloads",
|
||||||
mock.initConverse([], {
|
mock.initConverse([], {
|
||||||
'clear_messages_on_reconnection': true,
|
'clear_messages_on_reconnection': true,
|
||||||
@ -248,7 +247,6 @@ describe("Groupchats", function () {
|
|||||||
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>50</max></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>50</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -567,7 +565,7 @@ describe("Groupchats", function () {
|
|||||||
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
const muc_jid = 'lounge@montague.lit';
|
||||||
await mock.openAndEnterChatRoom(_converse, muc_jid , 'romeo');
|
await mock.openAndEnterChatRoom(_converse, muc_jid , 'romeo');
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const model = _converse.chatboxes.get(muc_jid);
|
||||||
const message = 'Hello world',
|
const message = 'Hello world',
|
||||||
nick = mock.chatroom_names[0],
|
nick = mock.chatroom_names[0],
|
||||||
msg = $msg({
|
msg = $msg({
|
||||||
@ -577,18 +575,19 @@ describe("Groupchats", function () {
|
|||||||
'type': 'groupchat'
|
'type': 'groupchat'
|
||||||
}).c('body').t(message).tree();
|
}).c('body').t(message).tree();
|
||||||
|
|
||||||
await view.model.handleMessageStanza(msg);
|
await model.handleMessageStanza(msg);
|
||||||
await view.model.close();
|
await u.waitUntil(() => document.querySelector('converse-chat-message'));
|
||||||
|
await model.close();
|
||||||
|
await u.waitUntil(() => !document.querySelector('converse-chat-message'));
|
||||||
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
_converse.connection.IQ_stanzas = [];
|
||||||
await mock.openAndEnterChatRoom(_converse, muc_jid , 'romeo');
|
await mock.openAndEnterChatRoom(_converse, muc_jid , 'romeo');
|
||||||
await u.waitUntil(() => view.querySelector('converse-chat-message'));
|
await u.waitUntil(() => document.querySelector('converse-chat-message'));
|
||||||
expect(view.model.messages.length).toBe(1);
|
expect(model.messages.length).toBe(1);
|
||||||
expect(view.querySelectorAll('converse-chat-message').length).toBe(1);
|
expect(document.querySelectorAll('converse-chat-message').length).toBe(1);
|
||||||
done()
|
done()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it("clears cached messages when it reconnects and clear_messages_on_reconnection is true",
|
it("clears cached messages when it reconnects and clear_messages_on_reconnection is true",
|
||||||
mock.initConverse([], {'clear_messages_on_reconnection': true}, async function (done, _converse) {
|
mock.initConverse([], {'clear_messages_on_reconnection': true}, async function (done, _converse) {
|
||||||
|
|
||||||
@ -734,7 +733,7 @@ describe("Groupchats", function () {
|
|||||||
.c('status', {code: '110'});
|
.c('status', {code: '110'});
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent);
|
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications')?.textContent);
|
||||||
expect(csntext.trim()).toEqual("some1 has entered the groupchat");
|
expect(csntext.trim()).toEqual("some1 has entered the groupchat");
|
||||||
|
|
||||||
await room_creation_promise;
|
await room_creation_promise;
|
||||||
@ -1228,6 +1227,10 @@ describe("Groupchats", function () {
|
|||||||
.c('status', {code: '110'});
|
.c('status', {code: '110'});
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
await u.waitUntil(() => view.querySelector('.configure-chatroom-button') !== null);
|
await u.waitUntil(() => view.querySelector('.configure-chatroom-button') !== null);
|
||||||
|
|
||||||
|
const own_occupant = view.model.getOwnOccupant();
|
||||||
|
await u.waitUntil(() => own_occupant.get('affiliation') === 'owner');
|
||||||
|
|
||||||
view.querySelector('.configure-chatroom-button').click();
|
view.querySelector('.configure-chatroom-button').click();
|
||||||
|
|
||||||
/* Check that an IQ is sent out, asking for the
|
/* Check that an IQ is sent out, asking for the
|
||||||
@ -1470,7 +1473,8 @@ describe("Groupchats", function () {
|
|||||||
view.model.rejoin();
|
view.model.rejoin();
|
||||||
// Test that members aren't removed when we reconnect
|
// Test that members aren't removed when we reconnect
|
||||||
expect(view.model.occupants.length).toBe(8);
|
expect(view.model.occupants.length).toBe(8);
|
||||||
await u.waitUntil(() => occupants.querySelectorAll('li').length === 8);
|
view.model.session.set('connection_status', converse.ROOMSTATUS.ENTERED); // Hack
|
||||||
|
await u.waitUntil(() => view.querySelectorAll('.occupant-list li').length === 8);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1607,12 +1611,12 @@ describe("Groupchats", function () {
|
|||||||
|
|
||||||
const view = _converse.chatboxviews.get('problematic@muc.montague.lit');
|
const view = _converse.chatboxviews.get('problematic@muc.montague.lit');
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-msg').textContent.trim())
|
const msg = await u.waitUntil(() => view.querySelector('.chatroom-body .disconnect-msg'));
|
||||||
.toBe('This groupchat no longer exists');
|
expect(msg.textContent.trim()).toBe('This groupchat no longer exists');
|
||||||
expect(view.querySelector('.chatroom-body .destroyed-reason').textContent.trim())
|
expect(view.querySelector('.chatroom-body .destroyed-reason').textContent.trim())
|
||||||
.toBe(`"We didn't like the name"`);
|
.toBe(`The following reason was given: "We didn't like the name"`);
|
||||||
expect(view.querySelector('.chatroom-body .moved-label').textContent.trim())
|
expect(view.querySelector('.chatroom-body .moved-label').textContent.trim())
|
||||||
.toBe('The conversation has moved. Click below to enter.');
|
.toBe('The conversation has moved to a new address. Click the link below to enter.');
|
||||||
expect(view.querySelector('.chatroom-body .moved-link').textContent.trim())
|
expect(view.querySelector('.chatroom-body .moved-link').textContent.trim())
|
||||||
.toBe(`other-room@chat.jabberfr.org`);
|
.toBe(`other-room@chat.jabberfr.org`);
|
||||||
done();
|
done();
|
||||||
@ -1649,11 +1653,10 @@ describe("Groupchats", function () {
|
|||||||
* node='x-roomuser-item'/>
|
* node='x-roomuser-item'/>
|
||||||
* </iq>
|
* </iq>
|
||||||
*/
|
*/
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => IQ_stanzas.filter(
|
||||||
IQ_stanzas,
|
|
||||||
s => sizzle(`iq[to="${muc_jid}"] query[node="x-roomuser-item"]`, s).length
|
s => sizzle(`iq[to="${muc_jid}"] query[node="x-roomuser-item"]`, s).length
|
||||||
).pop()
|
).pop());
|
||||||
);
|
|
||||||
expect(Strophe.serialize(iq)).toBe(
|
expect(Strophe.serialize(iq)).toBe(
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="lounge@montague.lit" `+
|
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="lounge@montague.lit" `+
|
||||||
`type="get" xmlns="jabber:client">`+
|
`type="get" xmlns="jabber:client">`+
|
||||||
@ -2116,8 +2119,7 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'coven@chat.shakespeare.lit';
|
const muc_jid = 'coven@chat.shakespeare.lit';
|
||||||
|
|
||||||
await _converse.api.rooms.open(muc_jid, { nick });
|
await _converse.api.rooms.open(muc_jid, { nick });
|
||||||
const stanza = await u.waitUntil(() => _.filter(
|
const stanza = await u.waitUntil(() => IQ_stanzas.filter(
|
||||||
IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -2195,13 +2197,13 @@ describe("Groupchats", function () {
|
|||||||
'muc_unmoderated',
|
'muc_unmoderated',
|
||||||
'muc_nonanonymous'
|
'muc_nonanonymous'
|
||||||
];
|
];
|
||||||
await mock.openAndEnterChatRoom(_converse, 'room@conference.example.org', 'romeo', features);
|
const muc_jid = 'room@conference.example.org';
|
||||||
const jid = 'room@conference.example.org';
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
|
||||||
const view = _converse.chatboxviews.get(jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
|
||||||
const info_el = view.querySelector(".show-muc-details-modal");
|
const info_el = view.querySelector(".show-muc-details-modal");
|
||||||
info_el.click();
|
info_el.click();
|
||||||
const modal = _converse.api.modal.get('muc-details-modal');
|
let modal = _converse.api.modal.get('muc-details-modal');
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
|
||||||
let features_list = modal.el.querySelector('.features-list');
|
let features_list = modal.el.querySelector('.features-list');
|
||||||
@ -2228,14 +2230,12 @@ describe("Groupchats", function () {
|
|||||||
expect(view.model.features.get('unsecured')).toBe(false);
|
expect(view.model.features.get('unsecured')).toBe(false);
|
||||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text').textContent.trim() === 'Room');
|
await u.waitUntil(() => view.querySelector('.chatbox-title__text').textContent.trim() === 'Room');
|
||||||
|
|
||||||
|
modal.el.querySelector('.close').click();
|
||||||
view.querySelector('.configure-chatroom-button').click();
|
view.querySelector('.configure-chatroom-button').click();
|
||||||
|
|
||||||
const IQs = _converse.connection.IQ_stanzas;
|
const IQs = _converse.connection.IQ_stanzas;
|
||||||
let iq = await u.waitUntil(() => _.filter(
|
const s = `iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_OWNER}"]`;
|
||||||
IQs,
|
let iq = await u.waitUntil(() => IQs.filter(iq => iq.querySelector(s)).pop());
|
||||||
iq => iq.querySelector(
|
|
||||||
`iq[to="${jid}"] query[xmlns="${Strophe.NS.MUC_OWNER}"]`
|
|
||||||
)).pop());
|
|
||||||
|
|
||||||
const response_el = u.toStanza(
|
const response_el = u.toStanza(
|
||||||
`<iq xmlns="jabber:client"
|
`<iq xmlns="jabber:client"
|
||||||
@ -2303,13 +2303,13 @@ describe("Groupchats", function () {
|
|||||||
</query>
|
</query>
|
||||||
</iq>`);
|
</iq>`);
|
||||||
_converse.connection._dataRecv(mock.createRequest(response_el));
|
_converse.connection._dataRecv(mock.createRequest(response_el));
|
||||||
const el = await u.waitUntil(() => document.querySelector('.chatroom-form legend'));
|
await u.waitUntil(() => document.querySelector('.chatroom-form input'));
|
||||||
expect(el.textContent.trim()).toBe("Configuration for room@conference.example.org");
|
expect(view.querySelector('.chatroom-form legend').textContent.trim()).toBe("Configuration for room@conference.example.org");
|
||||||
sizzle('[name="muc#roomconfig_membersonly"]', view).pop().click();
|
sizzle('[name="muc#roomconfig_membersonly"]', view).pop().click();
|
||||||
sizzle('[name="muc#roomconfig_roomname"]', view).pop().value = "New room name"
|
sizzle('[name="muc#roomconfig_roomname"]', view).pop().value = "New room name"
|
||||||
view.querySelector('.chatroom-form input[type="submit"]').click();
|
view.querySelector('.chatroom-form input[type="submit"]').click();
|
||||||
|
|
||||||
iq = await u.waitUntil(() => _.filter(IQs, iq => u.matchesSelector(iq, `iq[to="${jid}"][type="set"]`)).pop());
|
iq = await u.waitUntil(() => IQs.filter(iq => u.matchesSelector(iq, `iq[to="${muc_jid}"][type="set"]`)).pop());
|
||||||
const result = $iq({
|
const result = $iq({
|
||||||
"xmlns": "jabber:client",
|
"xmlns": "jabber:client",
|
||||||
"type": "result",
|
"type": "result",
|
||||||
@ -2321,14 +2321,13 @@ describe("Groupchats", function () {
|
|||||||
IQs.length = 0; // Empty the array
|
IQs.length = 0; // Empty the array
|
||||||
_converse.connection._dataRecv(mock.createRequest(result));
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
|
|
||||||
iq = await u.waitUntil(() => _.filter(
|
iq = await u.waitUntil(() => IQs.filter(
|
||||||
IQs,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
|
|
||||||
const features_stanza = $iq({
|
const features_stanza = $iq({
|
||||||
'from': jid,
|
'from': muc_jid,
|
||||||
'id': iq.getAttribute('id'),
|
'id': iq.getAttribute('id'),
|
||||||
'to': 'romeo@montague.lit/desktop',
|
'to': 'romeo@montague.lit/desktop',
|
||||||
'type': 'result'
|
'type': 'result'
|
||||||
@ -2360,6 +2359,11 @@ describe("Groupchats", function () {
|
|||||||
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
||||||
|
|
||||||
await u.waitUntil(() => new Promise(success => view.model.features.on('change', success)));
|
await u.waitUntil(() => new Promise(success => view.model.features.on('change', success)));
|
||||||
|
|
||||||
|
info_el.click();
|
||||||
|
modal = _converse.api.modal.get('muc-details-modal');
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
|
||||||
features_list = modal.el.querySelector('.features-list');
|
features_list = modal.el.querySelector('.features-list');
|
||||||
features_shown = features_list.textContent.split('\n').map(s => s.trim()).filter(s => s);
|
features_shown = features_list.textContent.split('\n').map(s => s.trim()).filter(s => s);
|
||||||
expect(features_shown.join(' ')).toBe(
|
expect(features_shown.join(' ')).toBe(
|
||||||
@ -2906,8 +2910,7 @@ describe("Groupchats", function () {
|
|||||||
});
|
});
|
||||||
_converse.connection.IQ_stanzas = [];
|
_converse.connection.IQ_stanzas = [];
|
||||||
_converse.connection._dataRecv(mock.createRequest(result));
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
iq_stanza = await u.waitUntil(() => _.filter(
|
iq_stanza = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector('iq[to="lounge@muc.montague.lit"][type="get"] item[affiliation="member"]')).pop()
|
iq => iq.querySelector('iq[to="lounge@muc.montague.lit"][type="get"] item[affiliation="member"]')).pop()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2930,8 +2933,7 @@ describe("Groupchats", function () {
|
|||||||
_converse.connection._dataRecv(mock.createRequest(result));
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
|
|
||||||
expect(view.model.occupants.length).toBe(2);
|
expect(view.model.occupants.length).toBe(2);
|
||||||
iq_stanza = await u.waitUntil(() => _.filter(
|
iq_stanza = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector('iq[to="lounge@muc.montague.lit"][type="get"] item[affiliation="owner"]')).pop()
|
iq => iq.querySelector('iq[to="lounge@muc.montague.lit"][type="get"] item[affiliation="owner"]')).pop()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2954,8 +2956,7 @@ describe("Groupchats", function () {
|
|||||||
_converse.connection._dataRecv(mock.createRequest(result));
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
|
|
||||||
expect(view.model.occupants.length).toBe(2);
|
expect(view.model.occupants.length).toBe(2);
|
||||||
iq_stanza = await u.waitUntil(() => _.filter(
|
iq_stanza = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector('iq[to="lounge@muc.montague.lit"][type="get"] item[affiliation="admin"]')).pop()
|
iq => iq.querySelector('iq[to="lounge@muc.montague.lit"][type="get"] item[affiliation="admin"]')).pop()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3721,7 +3722,6 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'protected';
|
const muc_jid = 'protected';
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
spyOn(view, 'renderPasswordForm').and.callThrough();
|
|
||||||
|
|
||||||
const presence = $pres().attrs({
|
const presence = $pres().attrs({
|
||||||
'from': `${muc_jid}/romeo`,
|
'from': `${muc_jid}/romeo`,
|
||||||
@ -3735,8 +3735,7 @@ describe("Groupchats", function () {
|
|||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
const chat_body = view.querySelector('.chatroom-body');
|
const chat_body = view.querySelector('.chatroom-body');
|
||||||
expect(view.renderPasswordForm).toHaveBeenCalled();
|
await u.waitUntil(() => chat_body.querySelectorAll('form.chatroom-form').length === 1);
|
||||||
expect(chat_body.querySelectorAll('form.chatroom-form').length).toBe(1);
|
|
||||||
expect(chat_body.querySelector('.chatroom-form label').textContent.trim())
|
expect(chat_body.querySelector('.chatroom-form label').textContent.trim())
|
||||||
.toBe('This groupchat requires a password');
|
.toBe('This groupchat requires a password');
|
||||||
|
|
||||||
@ -3755,8 +3754,7 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'members-only@muc.montague.lit'
|
const muc_jid = 'members-only@muc.montague.lit'
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -3791,8 +3789,8 @@ describe("Groupchats", function () {
|
|||||||
.c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child')?.textContent?.trim() ===
|
||||||
.toBe('You are not on the member list of this groupchat.');
|
'You are not on the member list of this groupchat.');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -3802,8 +3800,7 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'off-limits@muc.montague.lit'
|
const muc_jid = 'off-limits@muc.montague.lit'
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||||
|
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -3834,8 +3831,8 @@ describe("Groupchats", function () {
|
|||||||
.c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||||
.toBe('You have been banned from this groupchat.');
|
expect(el.textContent.trim()).toBe('You have been banned from this groupchat.');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -3844,8 +3841,7 @@ describe("Groupchats", function () {
|
|||||||
|
|
||||||
const muc_jid = 'conflicted@muc.montague.lit';
|
const muc_jid = 'conflicted@muc.montague.lit';
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -3876,8 +3872,8 @@ describe("Groupchats", function () {
|
|||||||
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
expect(view.querySelector('.muc-nickname-form .validation-message').textContent.trim())
|
const el = await u.waitUntil(() => view.querySelector('.muc-nickname-form .validation-message'));
|
||||||
.toBe('The nickname you chose is reserved or currently in use, please choose a different one.');
|
expect(el.textContent.trim()).toBe('The nickname you chose is reserved or currently in use, please choose a different one.');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -3948,8 +3944,7 @@ describe("Groupchats", function () {
|
|||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo')
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo')
|
||||||
|
|
||||||
// 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 iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -3974,8 +3969,8 @@ describe("Groupchats", function () {
|
|||||||
.c('error').attrs({by:'lounge@montague.lit', type:'cancel'})
|
.c('error').attrs({by:'lounge@montague.lit', type:'cancel'})
|
||||||
.c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||||
.toBe('You are not allowed to create new groupchats.');
|
expect(el.textContent.trim()).toBe('You are not allowed to create new groupchats.');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -3985,8 +3980,7 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'conformist@muc.montague.lit'
|
const muc_jid = 'conformist@muc.montague.lit'
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||||
|
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -4013,8 +4007,8 @@ describe("Groupchats", function () {
|
|||||||
.c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||||
.toBe("Your nickname doesn't conform to this groupchat's policies.");
|
expect(el.textContent.trim()).toBe("Your nickname doesn't conform to this groupchat's policies.");
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -4024,8 +4018,7 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'nonexistent@muc.montague.lit'
|
const muc_jid = 'nonexistent@muc.montague.lit'
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||||
|
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -4052,8 +4045,8 @@ describe("Groupchats", function () {
|
|||||||
.c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||||
.toBe("This groupchat does not (yet) exist.");
|
expect(el.textContent.trim()).toBe("This groupchat does not (yet) exist.");
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -4063,8 +4056,7 @@ describe("Groupchats", function () {
|
|||||||
const muc_jid = 'maxed-out@muc.montague.lit'
|
const muc_jid = 'maxed-out@muc.montague.lit'
|
||||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo')
|
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo')
|
||||||
|
|
||||||
const iq = await u.waitUntil(() => _.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => iq.querySelector(
|
iq => iq.querySelector(
|
||||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||||
)).pop());
|
)).pop());
|
||||||
@ -4091,8 +4083,8 @@ describe("Groupchats", function () {
|
|||||||
.c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
.c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||||
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||||
.toBe("This groupchat has reached its maximum number of participants.");
|
expect(el.textContent.trim()).toBe("This groupchat has reached its maximum number of participants.");
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -37,7 +37,9 @@ converse.MUC_TRAFFIC_STATES_LIST = Object.values(converse.MUC_TRAFFIC_STATES);
|
|||||||
converse.MUC_ROLE_CHANGES = { OP: 'op', DEOP: 'deop', VOICE: 'voice', MUTE: 'mute' };
|
converse.MUC_ROLE_CHANGES = { OP: 'op', DEOP: 'deop', VOICE: 'voice', MUTE: 'mute' };
|
||||||
converse.MUC_ROLE_CHANGES_LIST = Object.values(converse.MUC_ROLE_CHANGES);
|
converse.MUC_ROLE_CHANGES_LIST = Object.values(converse.MUC_ROLE_CHANGES);
|
||||||
|
|
||||||
converse.MUC_INFO_CODES = {
|
converse.MUC = {};
|
||||||
|
|
||||||
|
converse.MUC.INFO_CODES = {
|
||||||
'visibility_changes': ['100', '102', '103', '172', '173', '174'],
|
'visibility_changes': ['100', '102', '103', '172', '173', '174'],
|
||||||
'self': ['110'],
|
'self': ['110'],
|
||||||
'non_privacy_changes': ['104', '201'],
|
'non_privacy_changes': ['104', '201'],
|
||||||
@ -241,15 +243,15 @@ converse.plugins.add('converse-muc', {
|
|||||||
'muc_nickname_from_jid': false,
|
'muc_nickname_from_jid': false,
|
||||||
'muc_send_probes': false,
|
'muc_send_probes': false,
|
||||||
'muc_show_info_messages': [
|
'muc_show_info_messages': [
|
||||||
...converse.MUC_INFO_CODES.visibility_changes,
|
...converse.MUC.INFO_CODES.visibility_changes,
|
||||||
...converse.MUC_INFO_CODES.self,
|
...converse.MUC.INFO_CODES.self,
|
||||||
...converse.MUC_INFO_CODES.non_privacy_changes,
|
...converse.MUC.INFO_CODES.non_privacy_changes,
|
||||||
...converse.MUC_INFO_CODES.muc_logging_changes,
|
...converse.MUC.INFO_CODES.muc_logging_changes,
|
||||||
...converse.MUC_INFO_CODES.nickname_changes,
|
...converse.MUC.INFO_CODES.nickname_changes,
|
||||||
...converse.MUC_INFO_CODES.disconnect_messages,
|
...converse.MUC.INFO_CODES.disconnect_messages,
|
||||||
...converse.MUC_INFO_CODES.affiliation_changes,
|
...converse.MUC.INFO_CODES.affiliation_changes,
|
||||||
...converse.MUC_INFO_CODES.join_leave_events,
|
...converse.MUC.INFO_CODES.join_leave_events,
|
||||||
...converse.MUC_INFO_CODES.role_changes
|
...converse.MUC.INFO_CODES.role_changes
|
||||||
],
|
],
|
||||||
'muc_show_logs_before_join': false,
|
'muc_show_logs_before_join': false,
|
||||||
'muc_show_ogp_unfurls': true,
|
'muc_show_ogp_unfurls': true,
|
||||||
|
@ -2576,16 +2576,8 @@ const ChatRoomMixin = {
|
|||||||
// Accept default configuration
|
// Accept default configuration
|
||||||
this.sendConfiguration().then(() => this.refreshDiscoInfo());
|
this.sendConfiguration().then(() => this.refreshDiscoInfo());
|
||||||
} else {
|
} else {
|
||||||
/**
|
this.session.save({ 'view': converse.MUC.VIEWS.CONFIG });
|
||||||
* Triggered when a new room has been created which first needs to be configured
|
return;
|
||||||
* and when `auto_configure` is set to `false`.
|
|
||||||
* Used by `_converse.ChatRoomView` in order to know when to render the
|
|
||||||
* configuration form for a new room.
|
|
||||||
* @event _converse.ChatRoom#configurationNeeded
|
|
||||||
* @example _converse.api.listen.on('configurationNeeded', () => { ... });
|
|
||||||
*/
|
|
||||||
this.trigger('configurationNeeded');
|
|
||||||
return; // We haven't yet entered the groupchat, so bail here.
|
|
||||||
}
|
}
|
||||||
} else if (!this.features.get('fetched')) {
|
} else if (!this.features.get('fetched')) {
|
||||||
// The features for this groupchat weren't fetched.
|
// The features for this groupchat weren't fetched.
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
import tpl_muc_bookmark_form from './templates/form.js';
|
import tpl_muc_bookmark_form from './templates/form.js';
|
||||||
import { View } from '@converse/skeletor/src/view.js';
|
import { CustomElement } from 'components/element';
|
||||||
import { _converse } from '@converse/headless/core';
|
import { _converse, api } from "@converse/headless/core";
|
||||||
|
|
||||||
|
|
||||||
const MUCBookmarkForm = View.extend({
|
class MUCBookmarkForm extends CustomElement {
|
||||||
className: 'muc-bookmark-form chatroom-form-container',
|
|
||||||
|
|
||||||
initialize (attrs) {
|
static get properties () {
|
||||||
this.chatroomview = attrs.chatroomview;
|
return {
|
||||||
this.render();
|
'jid': { type: String }
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toHTML () {
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
return tpl_muc_bookmark_form(
|
return tpl_muc_bookmark_form(
|
||||||
Object.assign(this.model.toJSON(), {
|
Object.assign(this.model.toJSON(), {
|
||||||
'onCancel': ev => this.closeBookmarkForm(ev),
|
'onCancel': ev => this.closeBookmarkForm(ev),
|
||||||
'onSubmit': ev => this.onBookmarkFormSubmitted(ev)
|
'onSubmit': ev => this.onBookmarkFormSubmitted(ev)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
onBookmarkFormSubmitted (ev) {
|
onBookmarkFormSubmitted (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@ -29,12 +34,14 @@ const MUCBookmarkForm = View.extend({
|
|||||||
'nick': ev.target.querySelector('input[name=nick]')?.value
|
'nick': ev.target.querySelector('input[name=nick]')?.value
|
||||||
});
|
});
|
||||||
this.closeBookmarkForm(ev);
|
this.closeBookmarkForm(ev);
|
||||||
},
|
}
|
||||||
|
|
||||||
closeBookmarkForm (ev) {
|
closeBookmarkForm (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.chatroomview.closeForm();
|
this.model.session.save('view', null);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-bookmark-form', MUCBookmarkForm);
|
||||||
|
|
||||||
export default MUCBookmarkForm;
|
export default MUCBookmarkForm;
|
||||||
|
@ -22,7 +22,6 @@ export const bookmarkableChatRoomView = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderBookmarkForm () {
|
renderBookmarkForm () {
|
||||||
this.hideChatRoomContents();
|
|
||||||
if (!this.bookmark_form) {
|
if (!this.bookmark_form) {
|
||||||
this.bookmark_form = new _converse.MUCBookmarkForm({
|
this.bookmark_form = new _converse.MUCBookmarkForm({
|
||||||
'model': this.model,
|
'model': this.model,
|
||||||
@ -38,7 +37,7 @@ export const bookmarkableChatRoomView = {
|
|||||||
ev?.preventDefault();
|
ev?.preventDefault();
|
||||||
const models = _converse.bookmarks.where({ 'jid': this.model.get('jid') });
|
const models = _converse.bookmarks.where({ 'jid': this.model.get('jid') });
|
||||||
if (!models.length) {
|
if (!models.length) {
|
||||||
this.renderBookmarkForm();
|
this.model.session.set('view', converse.MUC.VIEWS.BOOKMARK);
|
||||||
} else {
|
} else {
|
||||||
models.forEach(model => model.destroy());
|
models.forEach(model => model.destroy());
|
||||||
}
|
}
|
||||||
@ -60,13 +59,13 @@ export const eventMethods = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addBookmarkViaEvent (ev) {
|
async addBookmarkViaEvent (ev) {
|
||||||
/* Add a bookmark as determined by the passed in
|
/* Add a bookmark as determined by the passed in
|
||||||
* event.
|
* event.
|
||||||
*/
|
*/
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
const jid = ev.target.getAttribute('data-room-jid');
|
const jid = ev.target.getAttribute('data-room-jid');
|
||||||
api.rooms.open(jid, { 'bring_to_foreground': true });
|
const room = await api.rooms.open(jid, { 'bring_to_foreground': true });
|
||||||
_converse.chatboxviews.get(jid).renderBookmarkForm();
|
room.session.save('view', converse.MUC.VIEWS.BOOKMARK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,12 +153,13 @@ export function minimize (ev, model) {
|
|||||||
}
|
}
|
||||||
// save the scroll position to restore it on maximize
|
// save the scroll position to restore it on maximize
|
||||||
const view = _converse.chatboxviews.get(model.get('jid'));
|
const view = _converse.chatboxviews.get(model.get('jid'));
|
||||||
const content = view.querySelector('.chat-content__messages');
|
const scroll = view.querySelector('.chat-content__messages')?.scrollTop;
|
||||||
const scroll = content.scrollTop;
|
if (scroll) {
|
||||||
if (model.collection && model.collection.browserStorage) {
|
if (model.collection && model.collection.browserStorage) {
|
||||||
model.save({ scroll });
|
model.save({ scroll });
|
||||||
} else {
|
} else {
|
||||||
model.set({ scroll });
|
model.set({ scroll });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
model.setChatState(_converse.INACTIVE);
|
model.setChatState(_converse.INACTIVE);
|
||||||
u.safeSave(model, {
|
u.safeSave(model, {
|
||||||
|
@ -1,43 +1,41 @@
|
|||||||
import log from "@converse/headless/log";
|
import log from "@converse/headless/log";
|
||||||
import tpl_muc_config_form from "./templates/muc-config-form.js";
|
import tpl_muc_config_form from "./templates/muc-config-form.js";
|
||||||
import { View } from '@converse/skeletor/src/view.js';
|
import { CustomElement } from 'components/element';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { api, converse } from "@converse/headless/core";
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
|
|
||||||
const { sizzle } = converse.env;
|
const { sizzle } = converse.env;
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
|
|
||||||
|
|
||||||
const MUCConfigForm = View.extend({
|
class MUCConfigForm extends CustomElement {
|
||||||
className: 'chatroom-form-container muc-config-form',
|
|
||||||
|
|
||||||
initialize (attrs) {
|
static get properties () {
|
||||||
this.chatroomview = attrs.chatroomview;
|
return {
|
||||||
this.listenTo(this.chatroomview.model.features, 'change:passwordprotected', this.render);
|
'jid': { type: String }
|
||||||
this.listenTo(this.chatroomview.model.features, 'change:config_stanza', this.render);
|
|
||||||
this.render();
|
|
||||||
},
|
|
||||||
|
|
||||||
toHTML () {
|
|
||||||
const stanza = u.toStanza(this.model.get('config_stanza'));
|
|
||||||
const whitelist = api.settings.get('roomconfig_whitelist');
|
|
||||||
let fields = sizzle('field', stanza);
|
|
||||||
if (whitelist.length) {
|
|
||||||
fields = fields.filter(f => whitelist.includes(f.getAttribute('var')));
|
|
||||||
}
|
}
|
||||||
const password_protected = this.model.features.get('passwordprotected');
|
}
|
||||||
const options = {
|
|
||||||
'new_password': !password_protected,
|
connectedCallback () {
|
||||||
'fixed_username': this.model.get('jid')
|
super.connectedCallback();
|
||||||
};
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
this.listenTo(this.model.features, 'change:passwordprotected', this.requestUpdate);
|
||||||
|
this.listenTo(this.model.session, 'change:config_stanza', this.requestUpdate);
|
||||||
|
this.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
return tpl_muc_config_form({
|
return tpl_muc_config_form({
|
||||||
'closeConfigForm': ev => this.closeConfigForm(ev),
|
'model': this.model,
|
||||||
'fields': fields.map(f => u.xForm2TemplateResult(f, stanza, options)),
|
'closeConfigForm': ev => this.closeForm(ev),
|
||||||
'instructions': stanza.querySelector('instructions')?.textContent,
|
|
||||||
'submitConfigForm': ev => this.submitConfigForm(ev),
|
'submitConfigForm': ev => this.submitConfigForm(ev),
|
||||||
'title': stanza.querySelector('title')?.textContent
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
|
async getConfig () {
|
||||||
|
const iq = await this.model.fetchRoomConfiguration();
|
||||||
|
this.model.session.set('config_stanza', iq.outerHTML);
|
||||||
|
}
|
||||||
|
|
||||||
async submitConfigForm (ev) {
|
async submitConfigForm (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@ -53,13 +51,15 @@ const MUCConfigForm = View.extend({
|
|||||||
api.alert('error', __('Error'), message);
|
api.alert('error', __('Error'), message);
|
||||||
}
|
}
|
||||||
await this.model.refreshDiscoInfo();
|
await this.model.refreshDiscoInfo();
|
||||||
this.chatroomview.closeForm();
|
this.closeForm();
|
||||||
},
|
|
||||||
|
|
||||||
closeConfigForm (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
this.chatroomview.closeForm();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
closeForm (ev) {
|
||||||
|
ev?.preventDefault?.();
|
||||||
|
this.model.session.set('view', null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-config-form', MUCConfigForm);
|
||||||
|
|
||||||
export default MUCConfigForm
|
export default MUCConfigForm
|
||||||
|
38
src/plugins/muc-views/destroyed.js
Normal file
38
src/plugins/muc-views/destroyed.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import tpl_muc_destroyed from './templates/muc-destroyed.js';
|
||||||
|
import { CustomElement } from 'components/element';
|
||||||
|
import { _converse, api } from "@converse/headless/core";
|
||||||
|
|
||||||
|
|
||||||
|
class MUCDestroyed extends CustomElement {
|
||||||
|
|
||||||
|
static get properties () {
|
||||||
|
return {
|
||||||
|
'jid': { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const reason = this.model.get('destroyed_reason');
|
||||||
|
const moved_jid = this.model.get('moved_jid');
|
||||||
|
return tpl_muc_destroyed({
|
||||||
|
moved_jid,
|
||||||
|
reason,
|
||||||
|
'onSwitch': ev => this.onSwitch(ev)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async onSwitch (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
const moved_jid = this.model.get('moved_jid');
|
||||||
|
const room = await api.rooms.get(moved_jid, {}, true);
|
||||||
|
room.maybeShow(true);
|
||||||
|
this.model.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-destroyed', MUCDestroyed);
|
38
src/plugins/muc-views/disconnected.js
Normal file
38
src/plugins/muc-views/disconnected.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import tpl_muc_disconnect from './templates/muc-disconnect.js';
|
||||||
|
import { CustomElement } from 'components/element';
|
||||||
|
import { __ } from 'i18n';
|
||||||
|
import { _converse, api } from "@converse/headless/core";
|
||||||
|
|
||||||
|
|
||||||
|
class MUCDisconnected extends CustomElement {
|
||||||
|
|
||||||
|
static get properties () {
|
||||||
|
return {
|
||||||
|
'jid': { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const message = this.model.get('disconnection_message');
|
||||||
|
if (!message) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const messages = [message];
|
||||||
|
const actor = this.model.get('disconnection_actor');
|
||||||
|
if (actor) {
|
||||||
|
messages.push(__('This action was done by %1$s.', actor));
|
||||||
|
}
|
||||||
|
const reason = this.model.get('disconnection_reason');
|
||||||
|
if (reason) {
|
||||||
|
messages.push(__('The reason given is: "%1$s".', reason));
|
||||||
|
}
|
||||||
|
return tpl_muc_disconnect(messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-disconnected', MUCDisconnected);
|
@ -56,7 +56,7 @@ export default class MUCHeading extends ChatHeading {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAndRenderConfigurationForm () {
|
getAndRenderConfigurationForm () {
|
||||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.getAndRenderConfigurationForm();
|
this.model.session.set('view', converse.MUC.VIEWS.CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
showModeratorToolsModal () {
|
showModeratorToolsModal () {
|
||||||
@ -86,7 +86,7 @@ export default class MUCHeading extends ChatHeading {
|
|||||||
buttons.push({
|
buttons.push({
|
||||||
'i18n_text': __('Configure'),
|
'i18n_text': __('Configure'),
|
||||||
'i18n_title': __('Configure this groupchat'),
|
'i18n_title': __('Configure this groupchat'),
|
||||||
'handler': ev => this.getAndRenderConfigurationForm(ev),
|
'handler': () => this.getAndRenderConfigurationForm(),
|
||||||
'a_class': 'configure-chatroom-button',
|
'a_class': 'configure-chatroom-button',
|
||||||
'icon_class': 'fa-wrench',
|
'icon_class': 'fa-wrench',
|
||||||
'name': 'configure'
|
'name': 'configure'
|
||||||
|
@ -19,6 +19,11 @@ import { api, converse, _converse } from '@converse/headless/core';
|
|||||||
|
|
||||||
const { Strophe } = converse.env;
|
const { Strophe } = converse.env;
|
||||||
|
|
||||||
|
converse.MUC.VIEWS = {
|
||||||
|
CONFIG: 'config-form',
|
||||||
|
BOOKMARK: 'bookmark-form'
|
||||||
|
}
|
||||||
|
|
||||||
function setMUCDomain (domain, controlboxview) {
|
function setMUCDomain (domain, controlboxview) {
|
||||||
controlboxview.querySelector('converse-rooms-list')
|
controlboxview.querySelector('converse-rooms-list')
|
||||||
.model.save('muc_domain', Strophe.getDomainFromJid(domain));
|
.model.save('muc_domain', Strophe.getDomainFromJid(domain));
|
||||||
|
@ -5,17 +5,10 @@ import BaseChatView from 'shared/chat/baseview.js';
|
|||||||
import ModeratorToolsModal from 'modals/moderator-tools.js';
|
import ModeratorToolsModal from 'modals/moderator-tools.js';
|
||||||
import log from '@converse/headless/log';
|
import log from '@converse/headless/log';
|
||||||
import tpl_muc from './templates/muc.js';
|
import tpl_muc from './templates/muc.js';
|
||||||
import tpl_muc_destroyed from './templates/muc-destroyed.js';
|
|
||||||
import tpl_muc_disconnect from './templates/muc-disconnect.js';
|
|
||||||
import tpl_muc_nickname_form from './templates/muc-nickname-form.js';
|
|
||||||
import tpl_spinner from 'templates/spinner.js';
|
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { _converse, api, converse } from '@converse/headless/core';
|
import { _converse, api, converse } from '@converse/headless/core';
|
||||||
import { render } from 'lit-html';
|
import { html, render } from "lit-html";
|
||||||
|
|
||||||
const { sizzle } = converse.env;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mixin which turns a ChatBoxView into a ChatRoomView
|
* Mixin which turns a ChatBoxView into a ChatRoomView
|
||||||
@ -25,8 +18,6 @@ const u = converse.env.utils;
|
|||||||
*/
|
*/
|
||||||
export default class MUCView extends BaseChatView {
|
export default class MUCView extends BaseChatView {
|
||||||
length = 300
|
length = 300
|
||||||
tagName = 'div'
|
|
||||||
className = 'chatbox chatroom hidden'
|
|
||||||
is_chatroom = true
|
is_chatroom = true
|
||||||
events = {
|
events = {
|
||||||
'click .chatbox-navback': 'showControlBox',
|
'click .chatbox-navback': 'showControlBox',
|
||||||
@ -34,14 +25,12 @@ export default class MUCView extends BaseChatView {
|
|||||||
// Arrow functions don't work here because you can't bind a different `this` param to them.
|
// Arrow functions don't work here because you can't bind a different `this` param to them.
|
||||||
'click .occupant-nick': function (ev) {
|
'click .occupant-nick': function (ev) {
|
||||||
this.insertIntoTextArea(ev.target.textContent);
|
this.insertIntoTextArea(ev.target.textContent);
|
||||||
},
|
}
|
||||||
'submit .muc-nickname-form': 'submitNickname'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize () {
|
async initialize () {
|
||||||
const jid = this.getAttribute('jid');
|
const jid = this.getAttribute('jid');
|
||||||
_converse.chatboxviews.add(jid, this);
|
_converse.chatboxviews.add(jid, this);
|
||||||
|
|
||||||
this.model = _converse.chatboxes.get(jid);
|
this.model = _converse.chatboxes.get(jid);
|
||||||
this.initDebounced();
|
this.initDebounced();
|
||||||
|
|
||||||
@ -49,18 +38,17 @@ export default class MUCView extends BaseChatView {
|
|||||||
this.listenTo(this.model, 'change:composing_spoiler', this.renderMessageForm);
|
this.listenTo(this.model, 'change:composing_spoiler', this.renderMessageForm);
|
||||||
this.listenTo(this.model, 'change:hidden', () => this.afterShown());
|
this.listenTo(this.model, 'change:hidden', () => this.afterShown());
|
||||||
this.listenTo(this.model, 'change:minimized', () => this.afterShown());
|
this.listenTo(this.model, 'change:minimized', () => this.afterShown());
|
||||||
this.listenTo(this.model, 'configurationNeeded', this.getAndRenderConfigurationForm);
|
|
||||||
this.listenTo(this.model, 'show', this.show);
|
this.listenTo(this.model, 'show', this.show);
|
||||||
this.listenTo(this.model.session, 'change:connection_status', this.renderAfterTransition);
|
this.listenTo(this.model.session, 'change:connection_status', this.updateAfterTransition);
|
||||||
|
this.listenTo(this.model.session, 'change:view', this.render);
|
||||||
|
|
||||||
await this.render();
|
await this.render();
|
||||||
|
|
||||||
// Need to be registered after render has been called.
|
// Need to be registered after render has been called.
|
||||||
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
|
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
|
||||||
this.listenTo(this.model.occupants, 'change:show', this.showJoinOrLeaveNotification);
|
this.listenTo(this.model.occupants, 'change:show', this.showJoinOrLeaveNotification);
|
||||||
this.listenTo(this.model.occupants, 'remove', this.onOccupantRemoved);
|
|
||||||
|
|
||||||
this.renderAfterTransition();
|
this.updateAfterTransition();
|
||||||
this.model.maybeShow();
|
this.model.maybeShow();
|
||||||
this.scrollDown();
|
this.scrollDown();
|
||||||
/**
|
/**
|
||||||
@ -76,47 +64,20 @@ export default class MUCView extends BaseChatView {
|
|||||||
this.setAttribute('id', this.model.get('box_id'));
|
this.setAttribute('id', this.model.get('box_id'));
|
||||||
render(
|
render(
|
||||||
tpl_muc({
|
tpl_muc({
|
||||||
'chatview': this,
|
'getNicknameRequiredTemplate': () => this.getNicknameRequiredTemplate(),
|
||||||
'conn_status': this.model.session.get('connection_status'),
|
|
||||||
'model': this.model,
|
'model': this.model,
|
||||||
'occupants': this.model.occupants,
|
|
||||||
'show_sidebar':
|
|
||||||
!this.model.get('hidden_occupants') &&
|
|
||||||
this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED,
|
|
||||||
'markScrolled': ev => this.markScrolled(ev),
|
|
||||||
'muc_show_logs_before_join': api.settings.get('muc_show_logs_before_join'),
|
|
||||||
'show_send_button': _converse.show_send_button
|
|
||||||
}),
|
}),
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
|
||||||
this.notifications = this.querySelector('.chat-content__notifications');
|
this.notifications = this.querySelector('.chat-content__notifications');
|
||||||
this.help_container = this.querySelector('.chat-content__help');
|
this.help_container = this.querySelector('.chat-content__help');
|
||||||
|
|
||||||
if (
|
|
||||||
!api.settings.get('muc_show_logs_before_join') &&
|
|
||||||
this.model.session.get('connection_status') !== converse.ROOMSTATUS.ENTERED
|
|
||||||
) {
|
|
||||||
this.showSpinner();
|
|
||||||
}
|
|
||||||
// Render header as late as possible since it's async and we
|
// Render header as late as possible since it's async and we
|
||||||
// want the rest of the DOM elements to be available ASAP.
|
// want the rest of the DOM elements to be available ASAP.
|
||||||
// Otherwise e.g. this.notifications is not yet defined when accessed elsewhere.
|
// Otherwise e.g. this.notifications is not yet defined when accessed elsewhere.
|
||||||
!this.model.get('hidden') && this.show();
|
!this.model.get('hidden') && this.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the nickname value from the form and then join the groupchat with it.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#submitNickname
|
|
||||||
* @param { Event }
|
|
||||||
*/
|
|
||||||
submitNickname (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
const nick = ev.target.nick.value.trim();
|
|
||||||
nick && this.model.join(nick);
|
|
||||||
}
|
|
||||||
|
|
||||||
showModeratorToolsModal (affiliation) {
|
showModeratorToolsModal (affiliation) {
|
||||||
if (!this.model.verifyRoles(['moderator'])) {
|
if (!this.model.verifyRoles(['moderator'])) {
|
||||||
return;
|
return;
|
||||||
@ -197,247 +158,28 @@ export default class MUCView extends BaseChatView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
getNicknameRequiredTemplate () {
|
||||||
* Renders a form given an IQ stanza containing the current
|
const jid = this.model.get('jid');
|
||||||
* groupchat configuration.
|
|
||||||
* Returns a promise which resolves once the user has
|
|
||||||
* either submitted the form, or canceled it.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#renderConfigurationForm
|
|
||||||
* @param { XMLElement } stanza: The IQ stanza containing the groupchat config.
|
|
||||||
*/
|
|
||||||
renderConfigurationForm (stanza) {
|
|
||||||
this.hideChatRoomContents();
|
|
||||||
this.model.save('config_stanza', stanza.outerHTML);
|
|
||||||
if (!this.config_form) {
|
|
||||||
this.config_form = new _converse.MUCConfigForm({
|
|
||||||
'model': this.model,
|
|
||||||
'chatroomview': this
|
|
||||||
});
|
|
||||||
const container_el = this.querySelector('.chatroom-body');
|
|
||||||
container_el.insertAdjacentElement('beforeend', this.config_form.el);
|
|
||||||
}
|
|
||||||
u.showElement(this.config_form.el);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders a form which allows the user to choose theirnickname.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#renderNicknameForm
|
|
||||||
*/
|
|
||||||
renderNicknameForm () {
|
|
||||||
if (api.settings.get('muc_show_logs_before_join')) {
|
if (api.settings.get('muc_show_logs_before_join')) {
|
||||||
this.hideSpinner();
|
return html`<converse-muc-chatarea jid="${jid}"></converse-muc-chatarea>`;
|
||||||
u.showElement(this.querySelector('converse-muc-chatarea'));
|
|
||||||
} else {
|
} else {
|
||||||
const form = this.querySelector('.muc-nickname-form');
|
return html`<converse-muc-nickname-form jid="${jid}"></converse-muc-nickname-form>`;
|
||||||
const tpl_result = tpl_muc_nickname_form(this.model.toJSON());
|
|
||||||
const form_el = u.getElementFromTemplateResult(tpl_result);
|
|
||||||
if (form) {
|
|
||||||
sizzle('.spinner', this).forEach(u.removeElement);
|
|
||||||
form.outerHTML = form_el.outerHTML;
|
|
||||||
} else {
|
|
||||||
this.hideChatRoomContents();
|
|
||||||
const container = this.querySelector('.chatroom-body');
|
|
||||||
container.insertAdjacentElement('beforeend', form_el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u.safeSave(this.model.session, { 'connection_status': converse.ROOMSTATUS.NICKNAME_REQUIRED });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the configuration form without submitting and return to the chat view.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#closeForm
|
|
||||||
*/
|
|
||||||
closeForm () {
|
|
||||||
sizzle('.chatroom-form-container', this).forEach(e => u.addClass('hidden', e));
|
|
||||||
this.renderAfterTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the process of configuring a groupchat, either by
|
|
||||||
* rendering a configuration form, or by auto-configuring
|
|
||||||
* based on the "roomconfig" data stored on the
|
|
||||||
* {@link _converse.ChatRoom}.
|
|
||||||
* Stores the new configuration on the {@link _converse.ChatRoom}
|
|
||||||
* once completed.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#getAndRenderConfigurationForm
|
|
||||||
* @param { Event } ev - DOM event that might be passed in if this
|
|
||||||
* method is called due to a user action. In this
|
|
||||||
* case, auto-configure won't happen, regardless of
|
|
||||||
* the settings.
|
|
||||||
*/
|
|
||||||
getAndRenderConfigurationForm () {
|
|
||||||
if (!this.config_form || !u.isVisible(this.config_form.el)) {
|
|
||||||
this.showSpinner();
|
|
||||||
this.model
|
|
||||||
.fetchRoomConfiguration()
|
|
||||||
.then(iq => this.renderConfigurationForm(iq))
|
|
||||||
.catch(e => log.error(e));
|
|
||||||
} else {
|
|
||||||
this.closeForm();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hideChatRoomContents () {
|
updateAfterTransition () {
|
||||||
const container_el = this.querySelector('.chatroom-body');
|
|
||||||
if (container_el !== null) {
|
|
||||||
[].forEach.call(container_el.children, child => child.classList.add('hidden'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPasswordForm () {
|
|
||||||
this.hideChatRoomContents();
|
|
||||||
const message = this.model.get('password_validation_message');
|
|
||||||
this.model.save('password_validation_message', undefined);
|
|
||||||
|
|
||||||
if (!this.password_form) {
|
|
||||||
this.password_form = new _converse.MUCPasswordForm({
|
|
||||||
'model': new Model({
|
|
||||||
'validation_message': message
|
|
||||||
}),
|
|
||||||
'chatroomview': this
|
|
||||||
});
|
|
||||||
const container_el = this.querySelector('.chatroom-body');
|
|
||||||
container_el.insertAdjacentElement('beforeend', this.password_form.el);
|
|
||||||
} else {
|
|
||||||
this.password_form.model.set('validation_message', message);
|
|
||||||
}
|
|
||||||
u.showElement(this.password_form.el);
|
|
||||||
this.model.session.save('connection_status', converse.ROOMSTATUS.PASSWORD_REQUIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
showDestroyedMessage () {
|
|
||||||
u.hideElement(this.querySelector('converse-muc-chatarea'));
|
|
||||||
sizzle('.spinner', this).forEach(u.removeElement);
|
|
||||||
|
|
||||||
const reason = this.model.get('destroyed_reason');
|
|
||||||
const moved_jid = this.model.get('moved_jid');
|
|
||||||
this.model.save({
|
|
||||||
'destroyed_reason': undefined,
|
|
||||||
'moved_jid': undefined
|
|
||||||
});
|
|
||||||
const container = this.querySelector('.disconnect-container');
|
|
||||||
render(tpl_muc_destroyed(moved_jid, reason), container);
|
|
||||||
const switch_el = container.querySelector('a.switch-chat');
|
|
||||||
if (switch_el) {
|
|
||||||
switch_el.addEventListener('click', async ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
const room = await api.rooms.get(moved_jid, null, true);
|
|
||||||
room.maybeShow(true);
|
|
||||||
this.model.destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
u.showElement(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
showDisconnectMessage () {
|
|
||||||
const message = this.model.get('disconnection_message');
|
|
||||||
if (!message) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
u.hideElement(this.querySelector('converse-muc-chatarea'));
|
|
||||||
sizzle('.spinner', this).forEach(u.removeElement);
|
|
||||||
|
|
||||||
const messages = [message];
|
|
||||||
const actor = this.model.get('disconnection_actor');
|
|
||||||
if (actor) {
|
|
||||||
messages.push(__('This action was done by %1$s.', actor));
|
|
||||||
}
|
|
||||||
const reason = this.model.get('disconnection_reason');
|
|
||||||
if (reason) {
|
|
||||||
messages.push(__('The reason given is: "%1$s".', reason));
|
|
||||||
}
|
|
||||||
this.model.save({
|
|
||||||
'disconnection_message': undefined,
|
|
||||||
'disconnection_reason': undefined,
|
|
||||||
'disconnection_actor': undefined
|
|
||||||
});
|
|
||||||
const container = this.querySelector('.disconnect-container');
|
|
||||||
render(tpl_muc_disconnect(messages), container);
|
|
||||||
u.showElement(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Working backwards, get today's most recent join/leave notification
|
|
||||||
* from the same user (if any exists) after the most recent chat message.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#getPreviousJoinOrLeaveNotification
|
|
||||||
* @param {HTMLElement} el
|
|
||||||
* @param {string} nick
|
|
||||||
*/
|
|
||||||
getPreviousJoinOrLeaveNotification (el, nick) { // eslint-disable-line class-methods-use-this
|
|
||||||
const today = new Date().toISOString().split('T')[0];
|
|
||||||
while (el !== null) {
|
|
||||||
if (!el.classList.contains('chat-info')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check whether el is still from today.
|
|
||||||
// We don't use `Dayjs.same` here, since it's about 4 times slower.
|
|
||||||
const date = el.getAttribute('data-isodate');
|
|
||||||
if (date && date.split('T')[0] !== today) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const data = el?.dataset || {};
|
|
||||||
if (data.join === nick || data.leave === nick || data.leavejoin === nick || data.joinleave === nick) {
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
el = el.previousElementSibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rerender the groupchat after some kind of transition. For
|
|
||||||
* example after the spinner has been removed or after a
|
|
||||||
* form has been submitted and removed.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#renderAfterTransition
|
|
||||||
*/
|
|
||||||
renderAfterTransition () {
|
|
||||||
const conn_status = this.model.session.get('connection_status');
|
const conn_status = this.model.session.get('connection_status');
|
||||||
if (conn_status === converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
if (conn_status === converse.ROOMSTATUS.CONNECTING) {
|
||||||
this.renderNicknameForm();
|
this.model.save({
|
||||||
} else if (conn_status === converse.ROOMSTATUS.PASSWORD_REQUIRED) {
|
'disconnection_actor': undefined,
|
||||||
this.renderPasswordForm();
|
'disconnection_message': undefined,
|
||||||
} else if (conn_status === converse.ROOMSTATUS.CONNECTING) {
|
'disconnection_reason': undefined,
|
||||||
this.showSpinner();
|
'moved_jid': undefined,
|
||||||
} else if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
'password_validation_message': undefined,
|
||||||
this.hideSpinner();
|
'reason': undefined,
|
||||||
this.hideChatRoomContents();
|
});
|
||||||
u.showElement(this.querySelector('converse-muc-chatarea'));
|
|
||||||
this.scrollDown();
|
|
||||||
this.maybeFocus();
|
|
||||||
} else if (conn_status === converse.ROOMSTATUS.DISCONNECTED) {
|
|
||||||
this.showDisconnectMessage();
|
|
||||||
} else if (conn_status === converse.ROOMSTATUS.DESTROYED) {
|
|
||||||
this.showDestroyedMessage();
|
|
||||||
}
|
}
|
||||||
}
|
this.render();
|
||||||
|
|
||||||
showSpinner () {
|
|
||||||
sizzle('.spinner', this).forEach(u.removeElement);
|
|
||||||
this.hideChatRoomContents();
|
|
||||||
const container_el = this.querySelector('.chatroom-body');
|
|
||||||
container_el.insertAdjacentElement('afterbegin', u.getElementFromTemplateResult(tpl_spinner()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the spinner is being shown and if so, hide it.
|
|
||||||
* Also make sure then that the chat area and occupants
|
|
||||||
* list are both visible.
|
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomView#hideSpinner
|
|
||||||
*/
|
|
||||||
hideSpinner () {
|
|
||||||
const spinner = this.querySelector('.spinner');
|
|
||||||
if (spinner !== null) {
|
|
||||||
u.removeElement(spinner);
|
|
||||||
this.renderAfterTransition();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
src/plugins/muc-views/nickname-form.js
Normal file
25
src/plugins/muc-views/nickname-form.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import tpl_muc_nickname_form from './templates/muc-nickname-form.js';
|
||||||
|
import { CustomElement } from 'components/element';
|
||||||
|
import { _converse, api } from "@converse/headless/core";
|
||||||
|
|
||||||
|
class MUCNicknameForm extends CustomElement {
|
||||||
|
|
||||||
|
static get properties () {
|
||||||
|
return {
|
||||||
|
'jid': { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return tpl_muc_nickname_form(this.model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-nickname-form', MUCNicknameForm);
|
||||||
|
|
||||||
|
export default MUCNicknameForm;
|
@ -1,30 +1,39 @@
|
|||||||
import tpl_muc_password_form from "./templates/muc-password-form.js";
|
import tpl_muc_password_form from "./templates/muc-password-form.js";
|
||||||
import { View } from '@converse/skeletor/src/view.js';
|
import { CustomElement } from 'components/element';
|
||||||
|
import { _converse, api } from "@converse/headless/core";
|
||||||
|
|
||||||
|
|
||||||
const MUCPasswordForm = View.extend({
|
class MUCPasswordForm extends CustomElement {
|
||||||
className: 'chatroom-form-container muc-password-form',
|
|
||||||
|
|
||||||
initialize (attrs) {
|
static get properties () {
|
||||||
this.chatroomview = attrs.chatroomview;
|
return {
|
||||||
this.listenTo(this.model, 'change:validation_message', this.render);
|
'jid': { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
this.listenTo(this.model, 'change:password_validation_message', this.render);
|
||||||
this.render();
|
this.render();
|
||||||
},
|
}
|
||||||
|
|
||||||
toHTML () {
|
render () {
|
||||||
return tpl_muc_password_form({
|
return tpl_muc_password_form({
|
||||||
'jid': this.model.get('jid'),
|
'jid': this.model.get('jid'),
|
||||||
'submitPassword': ev => this.submitPassword(ev),
|
'submitPassword': ev => this.submitPassword(ev),
|
||||||
'validation_message': this.model.get('validation_message')
|
'validation_message': this.model.get('password_validation_message')
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
submitPassword (ev) {
|
submitPassword (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
const password = this.el.querySelector('input[type=password]').value;
|
const password = this.querySelector('input[type=password]').value;
|
||||||
this.chatroomview.model.join(this.chatroomview.model.get('nick'), password);
|
this.model.join(this.model.get('nick'), password);
|
||||||
this.model.set('validation_message', null);
|
this.model.set('password_validation_message', null);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-password-form', MUCPasswordForm);
|
||||||
|
|
||||||
export default MUCPasswordForm;
|
export default MUCPasswordForm;
|
||||||
|
@ -16,7 +16,7 @@ export default (o) => {
|
|||||||
return (o.can_edit) ? tpl_can_edit() : html`<span class="muc-bottom-panel muc-bottom-panel--muted">${i18n_not_allowed}</span>`;
|
return (o.can_edit) ? tpl_can_edit() : html`<span class="muc-bottom-panel muc-bottom-panel--muted">${i18n_not_allowed}</span>`;
|
||||||
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
||||||
if (api.settings.get('muc_show_logs_before_join')) {
|
if (api.settings.get('muc_show_logs_before_join')) {
|
||||||
return html`<span class="muc-bottom-panel muc-bottom-panel--nickname">${tpl_muc_nickname_form(o.model.toJSON())}</span>`;
|
return html`<span class="muc-bottom-panel muc-bottom-panel--nickname">${tpl_muc_nickname_form(o.model)}</span>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
@ -1,20 +1,51 @@
|
|||||||
import { html } from "lit-html";
|
import tpl_spinner from 'templates/spinner.js';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
|
import { api, converse } from "@converse/headless/core";
|
||||||
|
import { html } from "lit-html";
|
||||||
|
|
||||||
|
const { sizzle } = converse.env;
|
||||||
|
const u = converse.env.utils;
|
||||||
|
|
||||||
export default (o) => {
|
export default (o) => {
|
||||||
|
const whitelist = api.settings.get('roomconfig_whitelist');
|
||||||
|
const config_stanza = o.model.session.get('config_stanza');
|
||||||
|
let fields = [];
|
||||||
|
let instructions = '';
|
||||||
|
let title;
|
||||||
|
if (config_stanza) {
|
||||||
|
const stanza = u.toStanza(config_stanza);
|
||||||
|
fields = sizzle('field', stanza);
|
||||||
|
if (whitelist.length) {
|
||||||
|
fields = fields.filter(f => whitelist.includes(f.getAttribute('var')));
|
||||||
|
}
|
||||||
|
const password_protected = o.model.features.get('passwordprotected');
|
||||||
|
const options = {
|
||||||
|
'new_password': !password_protected,
|
||||||
|
'fixed_username': o.model.get('jid')
|
||||||
|
};
|
||||||
|
fields = fields.map(f => u.xForm2TemplateResult(f, stanza, options));
|
||||||
|
instructions = stanza.querySelector('instructions')?.textContent;
|
||||||
|
title = stanza.querySelector('title')?.textContent;
|
||||||
|
} else {
|
||||||
|
title = __('Loading configuration form');
|
||||||
|
}
|
||||||
const i18n_save = __('Save');
|
const i18n_save = __('Save');
|
||||||
const i18n_cancel = __('Cancel');
|
const i18n_cancel = __('Cancel');
|
||||||
return html`
|
return html`
|
||||||
<form class="converse-form chatroom-form" autocomplete="off" @submit=${o.submitConfigForm}>
|
<form class="converse-form chatroom-form ${fields.length ? '' : 'converse-form--spinner'}"
|
||||||
|
autocomplete="off"
|
||||||
|
@submit=${o.submitConfigForm}>
|
||||||
|
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<legend>${o.title}</legend>
|
<legend class="centered">${title}</legend>
|
||||||
${ (o.title !== o.instructions) ? html`<p class="form-help">${o.instructions}</p>` : '' }
|
${ (title !== instructions) ? html`<p class="form-help">${instructions}</p>` : '' }
|
||||||
${ o.fields }
|
${ fields.length ? fields : tpl_spinner({'classes': 'hor_centered'}) }
|
||||||
</fieldset>
|
|
||||||
<fieldset>
|
|
||||||
<input type="submit" class="btn btn-primary" value="${i18n_save}">
|
|
||||||
<input type="button" class="btn btn-secondary button-cancel" value="${i18n_cancel}" @click=${o.closeConfigForm}>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
${ fields.length ? html`
|
||||||
|
<fieldset>
|
||||||
|
<input type="submit" class="btn btn-primary" value="${i18n_save}">
|
||||||
|
<input type="button" class="btn btn-secondary button-cancel" value="${i18n_cancel}" @click=${o.closeConfigForm}>
|
||||||
|
</fieldset>` : '' }
|
||||||
</form>
|
</form>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { html } from "lit-html";
|
import { html } from "lit-html";
|
||||||
|
|
||||||
|
const tpl_moved = (o) => {
|
||||||
const tpl_moved = (jid) => {
|
const i18n_moved = __('The conversation has moved to a new address. Click the link below to enter.');
|
||||||
const i18n_moved = __('The conversation has moved. Click below to enter.');
|
|
||||||
return html`
|
return html`
|
||||||
<p class="moved-label">${i18n_moved}</p>
|
<p class="moved-label">${i18n_moved}</p>
|
||||||
<p class="moved-link"><a class="switch-chat" href="#">${jid}</a></p>`;
|
<p class="moved-link">
|
||||||
|
<a class="switch-chat" @click=${ev => o.onSwitch(ev)}>${o.moved_jid}</a>
|
||||||
|
</p>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (jid, reason) => {
|
export default (o) => {
|
||||||
const i18n_non_existent = __('This groupchat no longer exists');
|
const i18n_non_existent = __('This groupchat no longer exists');
|
||||||
|
const i18n_reason = __('The following reason was given: "%1$s"', o.reason || '');
|
||||||
return html`
|
return html`
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<h3 class="alert-heading disconnect-msg">${i18n_non_existent}</h3>
|
<h3 class="alert-heading disconnect-msg">${i18n_non_existent}</h3>
|
||||||
${ reason ? html`<p class="destroyed-reason">"${reason}"</p>` : '' }
|
</div>
|
||||||
${ jid ? tpl_moved(jid) : '' }
|
${ o.reason ? html`<p class="destroyed-reason">${i18n_reason}</p>` : '' }
|
||||||
</div>`;
|
${ o.moved_jid ? tpl_moved(o) : '' }
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
@ -2,25 +2,33 @@ import { __ } from 'i18n';
|
|||||||
import { api } from "@converse/headless/core";
|
import { api } from "@converse/headless/core";
|
||||||
import { html } from "lit-html";
|
import { html } from "lit-html";
|
||||||
|
|
||||||
|
function submitNickname (ev, model) {
|
||||||
|
ev.preventDefault();
|
||||||
|
const nick = ev.target.nick.value.trim();
|
||||||
|
nick && model.join(nick);
|
||||||
|
}
|
||||||
|
|
||||||
export default (o) => {
|
export default (model) => {
|
||||||
const i18n_nickname = __('Nickname');
|
const i18n_nickname = __('Nickname');
|
||||||
const i18n_join = __('Enter groupchat');
|
const i18n_join = __('Enter groupchat');
|
||||||
const i18n_heading = api.settings.get('muc_show_logs_before_join') ?
|
const i18n_heading = api.settings.get('muc_show_logs_before_join') ?
|
||||||
__('Choose a nickname to enter') :
|
__('Choose a nickname to enter') :
|
||||||
__('Please choose your nickname');
|
__('Please choose your nickname');
|
||||||
|
|
||||||
|
const validation_message = model.get('nickname_validation_message');
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="chatroom-form-container muc-nickname-form">
|
<div class="chatroom-form-container muc-nickname-form"
|
||||||
|
@submit=${ev => submitNickname(ev, model)}>
|
||||||
<form class="converse-form chatroom-form converse-centered-form">
|
<form class="converse-form chatroom-form converse-centered-form">
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<label>${i18n_heading}</label>
|
<label>${i18n_heading}</label>
|
||||||
<p class="validation-message">${o.nickname_validation_message}</p>
|
<p class="validation-message">${validation_message}</p>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
required="required"
|
required="required"
|
||||||
name="nick"
|
name="nick"
|
||||||
value="${o.nick || ''}"
|
value="${model.get('nick') || ''}"
|
||||||
class="form-control ${o.nickname_validation_message ? 'error': ''}"
|
class="form-control ${validation_message ? 'error': ''}"
|
||||||
placeholder="${i18n_nickname}"/>
|
placeholder="${i18n_nickname}"/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
|
@ -1,15 +1,45 @@
|
|||||||
import '../chatarea.js';
|
|
||||||
import '../bottom-panel.js';
|
import '../bottom-panel.js';
|
||||||
|
import '../chatarea.js';
|
||||||
|
import '../config-form.js';
|
||||||
|
import '../destroyed.js';
|
||||||
|
import '../disconnected.js';
|
||||||
import '../heading.js';
|
import '../heading.js';
|
||||||
|
import '../nickname-form.js';
|
||||||
|
import '../password-form.js';
|
||||||
import '../sidebar.js';
|
import '../sidebar.js';
|
||||||
|
import tpl_spinner from 'templates/spinner.js';
|
||||||
|
import { converse } from "@converse/headless/core";
|
||||||
import { html } from "lit-html";
|
import { html } from "lit-html";
|
||||||
|
|
||||||
export default (o) => html`
|
|
||||||
<div class="flyout box-flyout">
|
function getChatRoomBody (o) {
|
||||||
<converse-dragresize></converse-dragresize>
|
const view = o.model.session.get('view');
|
||||||
<converse-muc-heading jid="${o.model.get('jid')}" class="chat-head chat-head-chatroom row no-gutters"></converse-muc-heading>
|
const jid = o.model.get('jid');
|
||||||
<div class="chat-body chatroom-body row no-gutters">
|
const RS = converse.ROOMSTATUS;
|
||||||
<converse-muc-chatarea jid="${o.model.get('jid')}"></converse-muc-chatarea>
|
const conn_status = o.model.session.get('connection_status');
|
||||||
|
|
||||||
|
if (view === converse.MUC.VIEWS.CONFIG) {
|
||||||
|
return html`<converse-muc-config-form class="muc-form-container" jid="${jid}"></converse-muc-config-form>`;
|
||||||
|
} else if (view === converse.MUC.VIEWS.BOOKMARK) {
|
||||||
|
return html`<converse-muc-bookmark-form class="muc-form-container" jid="${jid}"></converse-muc-bookmark-form>`;
|
||||||
|
} else {
|
||||||
|
return html`
|
||||||
|
${ conn_status == RS.PASSWORD_REQUIRED ? html`<converse-muc-password-form class="muc-form-container" jid="${jid}"></converse-muc-password-form>` : '' }
|
||||||
|
${ conn_status == RS.ENTERED ? html`<converse-muc-chatarea jid="${jid}"></converse-muc-chatarea>` : '' }
|
||||||
|
${ conn_status == RS.CONNECTING ? tpl_spinner() : '' }
|
||||||
|
${ conn_status == RS.NICKNAME_REQUIRED ? o.getNicknameRequiredTemplate() : '' }
|
||||||
|
${ conn_status == RS.DISCONNECTED ? html`<converse-muc-disconnected jid="${jid}"></converse-muc-disconnected>` : '' }
|
||||||
|
${ conn_status == RS.DESTROYED ? html`<converse-muc-destroyed jid="${jid}"></converse-muc-destroyed>` : '' }
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (o) => {
|
||||||
|
return html`
|
||||||
|
<div class="flyout box-flyout">
|
||||||
|
<converse-dragresize></converse-dragresize>
|
||||||
|
<converse-muc-heading jid="${o.model.get('jid')}" class="chat-head chat-head-chatroom row no-gutters"></converse-muc-heading>
|
||||||
|
<div class="chat-body chatroom-body row no-gutters">${getChatRoomBody(o)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
`;
|
||||||
`;
|
}
|
||||||
|
@ -20,7 +20,6 @@ const COMMAND_TO_ROLE = {
|
|||||||
'voice': 'participant'
|
'voice': 'participant'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export function getAutoCompleteListItem (text, input) {
|
export function getAutoCompleteListItem (text, input) {
|
||||||
input = input.trim();
|
input = input.trim();
|
||||||
const element = document.createElement('li');
|
const element = document.createElement('li');
|
||||||
|
Loading…
Reference in New Issue
Block a user