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 {
|
||||
.badge--muc {
|
||||
@ -324,7 +336,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatroom-form-container {
|
||||
.muc-form-container {
|
||||
background-color: white;
|
||||
border: 0;
|
||||
color: var(--text-color);
|
||||
@ -376,7 +388,7 @@
|
||||
padding: 0;
|
||||
height: 16em;
|
||||
|
||||
.chatroom-form-container {
|
||||
.muc-form-container {
|
||||
.chatroom-form {
|
||||
padding-top: 2em;
|
||||
padding-bottom: 0;
|
||||
@ -528,7 +540,7 @@
|
||||
}
|
||||
.chatroom-body {
|
||||
height: 100%;
|
||||
.chatroom-form-container {
|
||||
.muc-form-container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
@ -118,6 +118,10 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&.converse-form--spinner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.converse-centered-form {
|
||||
min-height: 66%;
|
||||
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 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);
|
||||
const toggle = view.querySelector('.toggle-bookmark');
|
||||
expect(toggle.title).toBe('Bookmark this groupchat');
|
||||
toggle.click();
|
||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
||||
|
||||
view.querySelector('.button-cancel').click();
|
||||
expect(view.closeForm).toHaveBeenCalled();
|
||||
const cancel_button = await u.waitUntil(() => view.querySelector('.button-cancel'));
|
||||
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(toggle.title).toBe('Bookmark this groupchat');
|
||||
|
||||
toggle.click();
|
||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
||||
|
||||
/* Client uploads data:
|
||||
* --------------------
|
||||
@ -75,13 +74,13 @@ describe("A chat room", function () {
|
||||
* </iq>
|
||||
*/
|
||||
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="autojoin"]').checked = 'checked';
|
||||
form.querySelector('input[name="nick"]').value = 'JC';
|
||||
|
||||
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(
|
||||
() => 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 () {},
|
||||
'keyCode': 13 // Enter
|
||||
}
|
||||
spyOn(_converse.connection, 'send');
|
||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||
bottom_panel.onKeyDown(enter_event);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||
const msg = _converse.connection.send.calls.all()[0].args[0];
|
||||
expect(msg.toLocaleString())
|
||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
|
||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||
const msg = await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop());
|
||||
expect(Strophe.serialize(msg))
|
||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.getAttribute("id")}" `+
|
||||
`to="lounge@montague.lit" type="groupchat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<body>hello Link Mauve</body>`+
|
||||
`<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"/>`+
|
||||
`<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>`);
|
||||
done();
|
||||
}));
|
||||
@ -374,7 +374,6 @@ describe("A sent groupchat message", function () {
|
||||
'stopPropagation': function stopPropagation () {},
|
||||
'keyCode': 13 // Enter
|
||||
}
|
||||
spyOn(_converse.connection, 'send');
|
||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||
bottom_panel.onKeyDown(enter_event);
|
||||
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?'
|
||||
);
|
||||
|
||||
const msg = _converse.connection.send.calls.all()[0].args[0];
|
||||
expect(msg.toLocaleString())
|
||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
|
||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||
const msg = await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop());
|
||||
expect(Strophe.serialize(msg))
|
||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${msg.getAttribute("id")}" `+
|
||||
`to="lounge@montague.lit" type="groupchat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<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="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"/>`+
|
||||
`<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>`);
|
||||
|
||||
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.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
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?';
|
||||
bottom_panel.onKeyDown(enter_event);
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||
'hello z3r0 gibson sw0rdf1sh, how are you?', 500);
|
||||
|
||||
const correction = _converse.connection.send.calls.all()[1].args[0];
|
||||
expect(correction.toLocaleString())
|
||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${correction.nodeTree.getAttribute("id")}" `+
|
||||
const correction = sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop();
|
||||
expect(Strophe.serialize(correction))
|
||||
.toBe(`<message from="romeo@montague.lit/orchard" id="${correction.getAttribute("id")}" `+
|
||||
`to="lounge@montague.lit" type="groupchat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<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="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"/>`+
|
||||
`<replace id="${msg.nodeTree.getAttribute("id")}" xmlns="urn:xmpp:message-correct:0"/>`+
|
||||
`<origin-id id="${correction.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||
`<replace id="${msg.getAttribute("id")}" xmlns="urn:xmpp:message-correct:0"/>`+
|
||||
`<origin-id id="${correction.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||
`</message>`);
|
||||
done();
|
||||
}));
|
||||
|
@ -1281,6 +1281,9 @@ describe("A Chat Message", function () {
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
const messages = _converse.connection.sent_stanzas.filter(s => s.nodeName === 'message');
|
||||
if (messages.length > 1) {
|
||||
debugger;
|
||||
}
|
||||
expect(messages.length).toBe(1);
|
||||
expect(Strophe.serialize(messages[0])).toBe(
|
||||
`<message id="${messages[0].getAttribute('id')}" to="tybalt@montague.lit" type="chat" xmlns="jabber:client">`+
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*global mock, converse */
|
||||
|
||||
const Model = converse.env.Model;
|
||||
const { sizzle, u } = converse.env;
|
||||
const { $pres, $iq, Strophe, sizzle, u } = converse.env;
|
||||
|
||||
describe("Groupchats", function () {
|
||||
|
||||
|
140
spec/muc.js
140
spec/muc.js
@ -147,7 +147,6 @@ describe("Groupchats", function () {
|
||||
return done();
|
||||
}));
|
||||
|
||||
|
||||
it("maintains its state across reloads",
|
||||
mock.initConverse([], {
|
||||
'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>`+
|
||||
`</query>`+
|
||||
`</iq>`);
|
||||
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -567,7 +565,7 @@ describe("Groupchats", function () {
|
||||
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
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',
|
||||
nick = mock.chatroom_names[0],
|
||||
msg = $msg({
|
||||
@ -577,18 +575,19 @@ describe("Groupchats", function () {
|
||||
'type': 'groupchat'
|
||||
}).c('body').t(message).tree();
|
||||
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await view.model.close();
|
||||
await model.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => document.querySelector('converse-chat-message'));
|
||||
await model.close();
|
||||
await u.waitUntil(() => !document.querySelector('converse-chat-message'));
|
||||
|
||||
_converse.connection.IQ_stanzas = [];
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid , 'romeo');
|
||||
await u.waitUntil(() => view.querySelector('converse-chat-message'));
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.querySelectorAll('converse-chat-message').length).toBe(1);
|
||||
await u.waitUntil(() => document.querySelector('converse-chat-message'));
|
||||
expect(model.messages.length).toBe(1);
|
||||
expect(document.querySelectorAll('converse-chat-message').length).toBe(1);
|
||||
done()
|
||||
}));
|
||||
|
||||
|
||||
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) {
|
||||
|
||||
@ -734,7 +733,7 @@ describe("Groupchats", function () {
|
||||
.c('status', {code: '110'});
|
||||
_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");
|
||||
|
||||
await room_creation_promise;
|
||||
@ -1228,6 +1227,10 @@ describe("Groupchats", function () {
|
||||
.c('status', {code: '110'});
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
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();
|
||||
|
||||
/* Check that an IQ is sent out, asking for the
|
||||
@ -1470,7 +1473,8 @@ describe("Groupchats", function () {
|
||||
view.model.rejoin();
|
||||
// Test that members aren't removed when we reconnect
|
||||
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();
|
||||
}));
|
||||
|
||||
@ -1607,12 +1611,12 @@ describe("Groupchats", function () {
|
||||
|
||||
const view = _converse.chatboxviews.get('problematic@muc.montague.lit');
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.querySelector('.chatroom-body .disconnect-msg').textContent.trim())
|
||||
.toBe('This groupchat no longer exists');
|
||||
const msg = await u.waitUntil(() => view.querySelector('.chatroom-body .disconnect-msg'));
|
||||
expect(msg.textContent.trim()).toBe('This groupchat no longer exists');
|
||||
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())
|
||||
.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())
|
||||
.toBe(`other-room@chat.jabberfr.org`);
|
||||
done();
|
||||
@ -1649,11 +1653,10 @@ describe("Groupchats", function () {
|
||||
* node='x-roomuser-item'/>
|
||||
* </iq>
|
||||
*/
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => IQ_stanzas.filter(
|
||||
s => sizzle(`iq[to="${muc_jid}"] query[node="x-roomuser-item"]`, s).length
|
||||
).pop()
|
||||
);
|
||||
).pop());
|
||||
|
||||
expect(Strophe.serialize(iq)).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="lounge@montague.lit" `+
|
||||
`type="get" xmlns="jabber:client">`+
|
||||
@ -2116,8 +2119,7 @@ describe("Groupchats", function () {
|
||||
const muc_jid = 'coven@chat.shakespeare.lit';
|
||||
|
||||
await _converse.api.rooms.open(muc_jid, { nick });
|
||||
const stanza = await u.waitUntil(() => _.filter(
|
||||
IQ_stanzas,
|
||||
const stanza = await u.waitUntil(() => IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -2195,13 +2197,13 @@ describe("Groupchats", function () {
|
||||
'muc_unmoderated',
|
||||
'muc_nonanonymous'
|
||||
];
|
||||
await mock.openAndEnterChatRoom(_converse, 'room@conference.example.org', 'romeo', features);
|
||||
const jid = 'room@conference.example.org';
|
||||
const view = _converse.chatboxviews.get(jid);
|
||||
const muc_jid = 'room@conference.example.org';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
|
||||
const info_el = view.querySelector(".show-muc-details-modal");
|
||||
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);
|
||||
|
||||
let features_list = modal.el.querySelector('.features-list');
|
||||
@ -2228,14 +2230,12 @@ describe("Groupchats", function () {
|
||||
expect(view.model.features.get('unsecured')).toBe(false);
|
||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text').textContent.trim() === 'Room');
|
||||
|
||||
modal.el.querySelector('.close').click();
|
||||
view.querySelector('.configure-chatroom-button').click();
|
||||
|
||||
const IQs = _converse.connection.IQ_stanzas;
|
||||
let iq = await u.waitUntil(() => _.filter(
|
||||
IQs,
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${jid}"] query[xmlns="${Strophe.NS.MUC_OWNER}"]`
|
||||
)).pop());
|
||||
const s = `iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_OWNER}"]`;
|
||||
let iq = await u.waitUntil(() => IQs.filter(iq => iq.querySelector(s)).pop());
|
||||
|
||||
const response_el = u.toStanza(
|
||||
`<iq xmlns="jabber:client"
|
||||
@ -2303,13 +2303,13 @@ describe("Groupchats", function () {
|
||||
</query>
|
||||
</iq>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(response_el));
|
||||
const el = await u.waitUntil(() => document.querySelector('.chatroom-form legend'));
|
||||
expect(el.textContent.trim()).toBe("Configuration for room@conference.example.org");
|
||||
await u.waitUntil(() => document.querySelector('.chatroom-form input'));
|
||||
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_roomname"]', view).pop().value = "New room name"
|
||||
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({
|
||||
"xmlns": "jabber:client",
|
||||
"type": "result",
|
||||
@ -2321,14 +2321,13 @@ describe("Groupchats", function () {
|
||||
IQs.length = 0; // Empty the array
|
||||
_converse.connection._dataRecv(mock.createRequest(result));
|
||||
|
||||
iq = await u.waitUntil(() => _.filter(
|
||||
IQs,
|
||||
iq = await u.waitUntil(() => IQs.filter(
|
||||
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());
|
||||
|
||||
const features_stanza = $iq({
|
||||
'from': jid,
|
||||
'from': muc_jid,
|
||||
'id': iq.getAttribute('id'),
|
||||
'to': 'romeo@montague.lit/desktop',
|
||||
'type': 'result'
|
||||
@ -2360,6 +2359,11 @@ describe("Groupchats", function () {
|
||||
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
||||
|
||||
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_shown = features_list.textContent.split('\n').map(s => s.trim()).filter(s => s);
|
||||
expect(features_shown.join(' ')).toBe(
|
||||
@ -2906,8 +2910,7 @@ describe("Groupchats", function () {
|
||||
});
|
||||
_converse.connection.IQ_stanzas = [];
|
||||
_converse.connection._dataRecv(mock.createRequest(result));
|
||||
iq_stanza = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
iq_stanza = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
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));
|
||||
|
||||
expect(view.model.occupants.length).toBe(2);
|
||||
iq_stanza = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
iq_stanza = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
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));
|
||||
|
||||
expect(view.model.occupants.length).toBe(2);
|
||||
iq_stanza = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
iq_stanza = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
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';
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
spyOn(view, 'renderPasswordForm').and.callThrough();
|
||||
|
||||
const presence = $pres().attrs({
|
||||
'from': `${muc_jid}/romeo`,
|
||||
@ -3735,8 +3735,7 @@ describe("Groupchats", function () {
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
|
||||
const chat_body = view.querySelector('.chatroom-body');
|
||||
expect(view.renderPasswordForm).toHaveBeenCalled();
|
||||
expect(chat_body.querySelectorAll('form.chatroom-form').length).toBe(1);
|
||||
await u.waitUntil(() => chat_body.querySelectorAll('form.chatroom-form').length === 1);
|
||||
expect(chat_body.querySelector('.chatroom-form label').textContent.trim())
|
||||
.toBe('This groupchat requires a password');
|
||||
|
||||
@ -3755,8 +3754,7 @@ describe("Groupchats", function () {
|
||||
const muc_jid = 'members-only@muc.montague.lit'
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -3791,8 +3789,8 @@ describe("Groupchats", function () {
|
||||
.c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
||||
.toBe('You are not on the member list of this groupchat.');
|
||||
await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child')?.textContent?.trim() ===
|
||||
'You are not on the member list of this groupchat.');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -3802,8 +3800,7 @@ describe("Groupchats", function () {
|
||||
const muc_jid = 'off-limits@muc.montague.lit'
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -3834,8 +3831,8 @@ describe("Groupchats", function () {
|
||||
.c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
|
||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
||||
.toBe('You have been banned from this groupchat.');
|
||||
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||
expect(el.textContent.trim()).toBe('You have been banned from this groupchat.');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -3844,8 +3841,7 @@ describe("Groupchats", function () {
|
||||
|
||||
const muc_jid = 'conflicted@muc.montague.lit';
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -3876,8 +3872,8 @@ describe("Groupchats", function () {
|
||||
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
|
||||
expect(view.querySelector('.muc-nickname-form .validation-message').textContent.trim())
|
||||
.toBe('The nickname you chose is reserved or currently in use, please choose a different one.');
|
||||
const el = await u.waitUntil(() => view.querySelector('.muc-nickname-form .validation-message'));
|
||||
expect(el.textContent.trim()).toBe('The nickname you chose is reserved or currently in use, please choose a different one.');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -3948,8 +3944,7 @@ describe("Groupchats", function () {
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo')
|
||||
|
||||
// We pretend this is a new room, so no disco info is returned.
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -3974,8 +3969,8 @@ describe("Groupchats", function () {
|
||||
.c('error').attrs({by:'lounge@montague.lit', type:'cancel'})
|
||||
.c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
||||
.toBe('You are not allowed to create new groupchats.');
|
||||
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||
expect(el.textContent.trim()).toBe('You are not allowed to create new groupchats.');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -3985,8 +3980,7 @@ describe("Groupchats", function () {
|
||||
const muc_jid = 'conformist@muc.montague.lit'
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -4013,8 +4007,8 @@ describe("Groupchats", function () {
|
||||
.c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
||||
.toBe("Your nickname doesn't conform to this groupchat's policies.");
|
||||
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||
expect(el.textContent.trim()).toBe("Your nickname doesn't conform to this groupchat's policies.");
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -4024,8 +4018,7 @@ describe("Groupchats", function () {
|
||||
const muc_jid = 'nonexistent@muc.montague.lit'
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -4052,8 +4045,8 @@ describe("Groupchats", function () {
|
||||
.c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
||||
.toBe("This groupchat does not (yet) exist.");
|
||||
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||
expect(el.textContent.trim()).toBe("This groupchat does not (yet) exist.");
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -4063,8 +4056,7 @@ describe("Groupchats", function () {
|
||||
const muc_jid = 'maxed-out@muc.montague.lit'
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo')
|
||||
|
||||
const iq = await u.waitUntil(() => _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(
|
||||
iq => iq.querySelector(
|
||||
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop());
|
||||
@ -4091,8 +4083,8 @@ describe("Groupchats", function () {
|
||||
.c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
|
||||
.toBe("This groupchat has reached its maximum number of participants.");
|
||||
const el = await u.waitUntil(() => view.querySelector('.chatroom-body converse-muc-disconnected .disconnect-msg:last-child'));
|
||||
expect(el.textContent.trim()).toBe("This groupchat has reached its maximum number of participants.");
|
||||
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_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'],
|
||||
'self': ['110'],
|
||||
'non_privacy_changes': ['104', '201'],
|
||||
@ -241,15 +243,15 @@ converse.plugins.add('converse-muc', {
|
||||
'muc_nickname_from_jid': false,
|
||||
'muc_send_probes': false,
|
||||
'muc_show_info_messages': [
|
||||
...converse.MUC_INFO_CODES.visibility_changes,
|
||||
...converse.MUC_INFO_CODES.self,
|
||||
...converse.MUC_INFO_CODES.non_privacy_changes,
|
||||
...converse.MUC_INFO_CODES.muc_logging_changes,
|
||||
...converse.MUC_INFO_CODES.nickname_changes,
|
||||
...converse.MUC_INFO_CODES.disconnect_messages,
|
||||
...converse.MUC_INFO_CODES.affiliation_changes,
|
||||
...converse.MUC_INFO_CODES.join_leave_events,
|
||||
...converse.MUC_INFO_CODES.role_changes
|
||||
...converse.MUC.INFO_CODES.visibility_changes,
|
||||
...converse.MUC.INFO_CODES.self,
|
||||
...converse.MUC.INFO_CODES.non_privacy_changes,
|
||||
...converse.MUC.INFO_CODES.muc_logging_changes,
|
||||
...converse.MUC.INFO_CODES.nickname_changes,
|
||||
...converse.MUC.INFO_CODES.disconnect_messages,
|
||||
...converse.MUC.INFO_CODES.affiliation_changes,
|
||||
...converse.MUC.INFO_CODES.join_leave_events,
|
||||
...converse.MUC.INFO_CODES.role_changes
|
||||
],
|
||||
'muc_show_logs_before_join': false,
|
||||
'muc_show_ogp_unfurls': true,
|
||||
|
@ -2576,16 +2576,8 @@ const ChatRoomMixin = {
|
||||
// Accept default configuration
|
||||
this.sendConfiguration().then(() => this.refreshDiscoInfo());
|
||||
} else {
|
||||
/**
|
||||
* Triggered when a new room has been created which first needs to be configured
|
||||
* 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.
|
||||
this.session.save({ 'view': converse.MUC.VIEWS.CONFIG });
|
||||
return;
|
||||
}
|
||||
} else if (!this.features.get('fetched')) {
|
||||
// The features for this groupchat weren't fetched.
|
||||
|
@ -1,24 +1,29 @@
|
||||
import tpl_muc_bookmark_form from './templates/form.js';
|
||||
import { View } from '@converse/skeletor/src/view.js';
|
||||
import { _converse } from '@converse/headless/core';
|
||||
import { CustomElement } from 'components/element';
|
||||
import { _converse, api } from "@converse/headless/core";
|
||||
|
||||
|
||||
const MUCBookmarkForm = View.extend({
|
||||
className: 'muc-bookmark-form chatroom-form-container',
|
||||
class MUCBookmarkForm extends CustomElement {
|
||||
|
||||
initialize (attrs) {
|
||||
this.chatroomview = attrs.chatroomview;
|
||||
this.render();
|
||||
},
|
||||
static get properties () {
|
||||
return {
|
||||
'jid': { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
toHTML () {
|
||||
connectedCallback () {
|
||||
super.connectedCallback();
|
||||
this.model = _converse.chatboxes.get(this.jid);
|
||||
}
|
||||
|
||||
render () {
|
||||
return tpl_muc_bookmark_form(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
'onCancel': ev => this.closeBookmarkForm(ev),
|
||||
'onSubmit': ev => this.onBookmarkFormSubmitted(ev)
|
||||
})
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
onBookmarkFormSubmitted (ev) {
|
||||
ev.preventDefault();
|
||||
@ -29,12 +34,14 @@ const MUCBookmarkForm = View.extend({
|
||||
'nick': ev.target.querySelector('input[name=nick]')?.value
|
||||
});
|
||||
this.closeBookmarkForm(ev);
|
||||
},
|
||||
}
|
||||
|
||||
closeBookmarkForm (ev) {
|
||||
ev.preventDefault();
|
||||
this.chatroomview.closeForm();
|
||||
this.model.session.save('view', null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
api.elements.define('converse-muc-bookmark-form', MUCBookmarkForm);
|
||||
|
||||
export default MUCBookmarkForm;
|
||||
|
@ -22,7 +22,6 @@ export const bookmarkableChatRoomView = {
|
||||
},
|
||||
|
||||
renderBookmarkForm () {
|
||||
this.hideChatRoomContents();
|
||||
if (!this.bookmark_form) {
|
||||
this.bookmark_form = new _converse.MUCBookmarkForm({
|
||||
'model': this.model,
|
||||
@ -38,7 +37,7 @@ export const bookmarkableChatRoomView = {
|
||||
ev?.preventDefault();
|
||||
const models = _converse.bookmarks.where({ 'jid': this.model.get('jid') });
|
||||
if (!models.length) {
|
||||
this.renderBookmarkForm();
|
||||
this.model.session.set('view', converse.MUC.VIEWS.BOOKMARK);
|
||||
} else {
|
||||
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
|
||||
* event.
|
||||
*/
|
||||
ev.preventDefault();
|
||||
const jid = ev.target.getAttribute('data-room-jid');
|
||||
api.rooms.open(jid, { 'bring_to_foreground': true });
|
||||
_converse.chatboxviews.get(jid).renderBookmarkForm();
|
||||
const room = await api.rooms.open(jid, { 'bring_to_foreground': true });
|
||||
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
|
||||
const view = _converse.chatboxviews.get(model.get('jid'));
|
||||
const content = view.querySelector('.chat-content__messages');
|
||||
const scroll = content.scrollTop;
|
||||
if (model.collection && model.collection.browserStorage) {
|
||||
model.save({ scroll });
|
||||
} else {
|
||||
model.set({ scroll });
|
||||
const scroll = view.querySelector('.chat-content__messages')?.scrollTop;
|
||||
if (scroll) {
|
||||
if (model.collection && model.collection.browserStorage) {
|
||||
model.save({ scroll });
|
||||
} else {
|
||||
model.set({ scroll });
|
||||
}
|
||||
}
|
||||
model.setChatState(_converse.INACTIVE);
|
||||
u.safeSave(model, {
|
||||
|
@ -1,43 +1,41 @@
|
||||
import log from "@converse/headless/log";
|
||||
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 { api, converse } from "@converse/headless/core";
|
||||
import { _converse, api, converse } from "@converse/headless/core";
|
||||
|
||||
const { sizzle } = converse.env;
|
||||
const u = converse.env.utils;
|
||||
|
||||
|
||||
const MUCConfigForm = View.extend({
|
||||
className: 'chatroom-form-container muc-config-form',
|
||||
class MUCConfigForm extends CustomElement {
|
||||
|
||||
initialize (attrs) {
|
||||
this.chatroomview = attrs.chatroomview;
|
||||
this.listenTo(this.chatroomview.model.features, 'change:passwordprotected', this.render);
|
||||
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')));
|
||||
static get properties () {
|
||||
return {
|
||||
'jid': { type: String }
|
||||
}
|
||||
const password_protected = this.model.features.get('passwordprotected');
|
||||
const options = {
|
||||
'new_password': !password_protected,
|
||||
'fixed_username': this.model.get('jid')
|
||||
};
|
||||
}
|
||||
|
||||
connectedCallback () {
|
||||
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({
|
||||
'closeConfigForm': ev => this.closeConfigForm(ev),
|
||||
'fields': fields.map(f => u.xForm2TemplateResult(f, stanza, options)),
|
||||
'instructions': stanza.querySelector('instructions')?.textContent,
|
||||
'model': this.model,
|
||||
'closeConfigForm': ev => this.closeForm(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) {
|
||||
ev.preventDefault();
|
||||
@ -53,13 +51,15 @@ const MUCConfigForm = View.extend({
|
||||
api.alert('error', __('Error'), message);
|
||||
}
|
||||
await this.model.refreshDiscoInfo();
|
||||
this.chatroomview.closeForm();
|
||||
},
|
||||
|
||||
closeConfigForm (ev) {
|
||||
ev.preventDefault();
|
||||
this.chatroomview.closeForm();
|
||||
this.closeForm();
|
||||
}
|
||||
});
|
||||
|
||||
closeForm (ev) {
|
||||
ev?.preventDefault?.();
|
||||
this.model.session.set('view', null);
|
||||
}
|
||||
}
|
||||
|
||||
api.elements.define('converse-muc-config-form', 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 () {
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.getAndRenderConfigurationForm();
|
||||
this.model.session.set('view', converse.MUC.VIEWS.CONFIG);
|
||||
}
|
||||
|
||||
showModeratorToolsModal () {
|
||||
@ -86,7 +86,7 @@ export default class MUCHeading extends ChatHeading {
|
||||
buttons.push({
|
||||
'i18n_text': __('Configure'),
|
||||
'i18n_title': __('Configure this groupchat'),
|
||||
'handler': ev => this.getAndRenderConfigurationForm(ev),
|
||||
'handler': () => this.getAndRenderConfigurationForm(),
|
||||
'a_class': 'configure-chatroom-button',
|
||||
'icon_class': 'fa-wrench',
|
||||
'name': 'configure'
|
||||
|
@ -19,6 +19,11 @@ import { api, converse, _converse } from '@converse/headless/core';
|
||||
|
||||
const { Strophe } = converse.env;
|
||||
|
||||
converse.MUC.VIEWS = {
|
||||
CONFIG: 'config-form',
|
||||
BOOKMARK: 'bookmark-form'
|
||||
}
|
||||
|
||||
function setMUCDomain (domain, controlboxview) {
|
||||
controlboxview.querySelector('converse-rooms-list')
|
||||
.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 log from '@converse/headless/log';
|
||||
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 { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { render } from 'lit-html';
|
||||
|
||||
const { sizzle } = converse.env;
|
||||
const u = converse.env.utils;
|
||||
import { html, render } from "lit-html";
|
||||
|
||||
/**
|
||||
* Mixin which turns a ChatBoxView into a ChatRoomView
|
||||
@ -25,8 +18,6 @@ const u = converse.env.utils;
|
||||
*/
|
||||
export default class MUCView extends BaseChatView {
|
||||
length = 300
|
||||
tagName = 'div'
|
||||
className = 'chatbox chatroom hidden'
|
||||
is_chatroom = true
|
||||
events = {
|
||||
'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.
|
||||
'click .occupant-nick': function (ev) {
|
||||
this.insertIntoTextArea(ev.target.textContent);
|
||||
},
|
||||
'submit .muc-nickname-form': 'submitNickname'
|
||||
}
|
||||
}
|
||||
|
||||
async initialize () {
|
||||
const jid = this.getAttribute('jid');
|
||||
_converse.chatboxviews.add(jid, this);
|
||||
|
||||
this.model = _converse.chatboxes.get(jid);
|
||||
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:hidden', () => 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.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();
|
||||
|
||||
// Need to be registered after render has been called.
|
||||
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
|
||||
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.scrollDown();
|
||||
/**
|
||||
@ -76,47 +64,20 @@ export default class MUCView extends BaseChatView {
|
||||
this.setAttribute('id', this.model.get('box_id'));
|
||||
render(
|
||||
tpl_muc({
|
||||
'chatview': this,
|
||||
'conn_status': this.model.session.get('connection_status'),
|
||||
'getNicknameRequiredTemplate': () => this.getNicknameRequiredTemplate(),
|
||||
'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.notifications = this.querySelector('.chat-content__notifications');
|
||||
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
|
||||
// want the rest of the DOM elements to be available ASAP.
|
||||
// Otherwise e.g. this.notifications is not yet defined when accessed elsewhere.
|
||||
!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) {
|
||||
if (!this.model.verifyRoles(['moderator'])) {
|
||||
return;
|
||||
@ -197,247 +158,28 @@ export default class MUCView extends BaseChatView {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a form given an IQ stanza containing the current
|
||||
* 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 () {
|
||||
getNicknameRequiredTemplate () {
|
||||
const jid = this.model.get('jid');
|
||||
if (api.settings.get('muc_show_logs_before_join')) {
|
||||
this.hideSpinner();
|
||||
u.showElement(this.querySelector('converse-muc-chatarea'));
|
||||
return html`<converse-muc-chatarea jid="${jid}"></converse-muc-chatarea>`;
|
||||
} else {
|
||||
const form = this.querySelector('.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();
|
||||
return html`<converse-muc-nickname-form jid="${jid}"></converse-muc-nickname-form>`;
|
||||
}
|
||||
}
|
||||
|
||||
hideChatRoomContents () {
|
||||
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 () {
|
||||
updateAfterTransition () {
|
||||
const conn_status = this.model.session.get('connection_status');
|
||||
if (conn_status === converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
||||
this.renderNicknameForm();
|
||||
} else if (conn_status === converse.ROOMSTATUS.PASSWORD_REQUIRED) {
|
||||
this.renderPasswordForm();
|
||||
} else if (conn_status === converse.ROOMSTATUS.CONNECTING) {
|
||||
this.showSpinner();
|
||||
} else if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
||||
this.hideSpinner();
|
||||
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();
|
||||
if (conn_status === converse.ROOMSTATUS.CONNECTING) {
|
||||
this.model.save({
|
||||
'disconnection_actor': undefined,
|
||||
'disconnection_message': undefined,
|
||||
'disconnection_reason': undefined,
|
||||
'moved_jid': undefined,
|
||||
'password_validation_message': undefined,
|
||||
'reason': undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
|
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 { View } from '@converse/skeletor/src/view.js';
|
||||
import { CustomElement } from 'components/element';
|
||||
import { _converse, api } from "@converse/headless/core";
|
||||
|
||||
|
||||
const MUCPasswordForm = View.extend({
|
||||
className: 'chatroom-form-container muc-password-form',
|
||||
class MUCPasswordForm extends CustomElement {
|
||||
|
||||
initialize (attrs) {
|
||||
this.chatroomview = attrs.chatroomview;
|
||||
this.listenTo(this.model, 'change:validation_message', this.render);
|
||||
static get properties () {
|
||||
return {
|
||||
'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();
|
||||
},
|
||||
}
|
||||
|
||||
toHTML () {
|
||||
render () {
|
||||
return tpl_muc_password_form({
|
||||
'jid': this.model.get('jid'),
|
||||
'submitPassword': ev => this.submitPassword(ev),
|
||||
'validation_message': this.model.get('validation_message')
|
||||
'validation_message': this.model.get('password_validation_message')
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
submitPassword (ev) {
|
||||
ev.preventDefault();
|
||||
const password = this.el.querySelector('input[type=password]').value;
|
||||
this.chatroomview.model.join(this.chatroomview.model.get('nick'), password);
|
||||
this.model.set('validation_message', null);
|
||||
const password = this.querySelector('input[type=password]').value;
|
||||
this.model.join(this.model.get('nick'), password);
|
||||
this.model.set('password_validation_message', null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
api.elements.define('converse-muc-password-form', 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>`;
|
||||
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
||||
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 {
|
||||
return '';
|
||||
|
@ -1,20 +1,51 @@
|
||||
import { html } from "lit-html";
|
||||
import tpl_spinner from 'templates/spinner.js';
|
||||
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) => {
|
||||
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_cancel = __('Cancel');
|
||||
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">
|
||||
<legend>${o.title}</legend>
|
||||
${ (o.title !== o.instructions) ? html`<p class="form-help">${o.instructions}</p>` : '' }
|
||||
${ o.fields }
|
||||
</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}>
|
||||
<legend class="centered">${title}</legend>
|
||||
${ (title !== instructions) ? html`<p class="form-help">${instructions}</p>` : '' }
|
||||
${ fields.length ? fields : tpl_spinner({'classes': 'hor_centered'}) }
|
||||
</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>
|
||||
`;
|
||||
}
|
||||
|
@ -1,20 +1,23 @@
|
||||
import { __ } from 'i18n';
|
||||
import { html } from "lit-html";
|
||||
|
||||
|
||||
const tpl_moved = (jid) => {
|
||||
const i18n_moved = __('The conversation has moved. Click below to enter.');
|
||||
const tpl_moved = (o) => {
|
||||
const i18n_moved = __('The conversation has moved to a new address. Click the link below to enter.');
|
||||
return html`
|
||||
<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_reason = __('The following reason was given: "%1$s"', o.reason || '');
|
||||
return html`
|
||||
<div class="alert alert-danger">
|
||||
<h3 class="alert-heading disconnect-msg">${i18n_non_existent}</h3>
|
||||
${ reason ? html`<p class="destroyed-reason">"${reason}"</p>` : '' }
|
||||
${ jid ? tpl_moved(jid) : '' }
|
||||
</div>`;
|
||||
</div>
|
||||
${ o.reason ? html`<p class="destroyed-reason">${i18n_reason}</p>` : '' }
|
||||
${ o.moved_jid ? tpl_moved(o) : '' }
|
||||
`;
|
||||
}
|
||||
|
@ -2,25 +2,33 @@ import { __ } from 'i18n';
|
||||
import { api } from "@converse/headless/core";
|
||||
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_join = __('Enter groupchat');
|
||||
const i18n_heading = api.settings.get('muc_show_logs_before_join') ?
|
||||
__('Choose a nickname to enter') :
|
||||
__('Please choose your nickname');
|
||||
|
||||
const validation_message = model.get('nickname_validation_message');
|
||||
|
||||
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">
|
||||
<fieldset class="form-group">
|
||||
<label>${i18n_heading}</label>
|
||||
<p class="validation-message">${o.nickname_validation_message}</p>
|
||||
<p class="validation-message">${validation_message}</p>
|
||||
<input type="text"
|
||||
required="required"
|
||||
name="nick"
|
||||
value="${o.nick || ''}"
|
||||
class="form-control ${o.nickname_validation_message ? 'error': ''}"
|
||||
value="${model.get('nick') || ''}"
|
||||
class="form-control ${validation_message ? 'error': ''}"
|
||||
placeholder="${i18n_nickname}"/>
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
|
@ -1,15 +1,45 @@
|
||||
import '../chatarea.js';
|
||||
import '../bottom-panel.js';
|
||||
import '../chatarea.js';
|
||||
import '../config-form.js';
|
||||
import '../destroyed.js';
|
||||
import '../disconnected.js';
|
||||
import '../heading.js';
|
||||
import '../nickname-form.js';
|
||||
import '../password-form.js';
|
||||
import '../sidebar.js';
|
||||
import tpl_spinner from 'templates/spinner.js';
|
||||
import { converse } from "@converse/headless/core";
|
||||
import { html } from "lit-html";
|
||||
|
||||
export default (o) => 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">
|
||||
<converse-muc-chatarea jid="${o.model.get('jid')}"></converse-muc-chatarea>
|
||||
|
||||
function getChatRoomBody (o) {
|
||||
const view = o.model.session.get('view');
|
||||
const jid = o.model.get('jid');
|
||||
const RS = converse.ROOMSTATUS;
|
||||
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>
|
||||
`;
|
||||
`;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ const COMMAND_TO_ROLE = {
|
||||
'voice': 'participant'
|
||||
};
|
||||
|
||||
|
||||
export function getAutoCompleteListItem (text, input) {
|
||||
input = input.trim();
|
||||
const element = document.createElement('li');
|
||||
|
Loading…
Reference in New Issue
Block a user