Improve how the muc_domain
setting is populated via disco
Remove brittle code that uses `querySelector` to get the rooms list model. This code was causing a TypeError due to a race condition.
This commit is contained in:
parent
99ae9a9850
commit
8e1c3e47df
|
@ -3,6 +3,7 @@
|
||||||
## 9.1.1 (Unreleased)
|
## 9.1.1 (Unreleased)
|
||||||
|
|
||||||
- GIFs don't render inside unfurls and cause a TypeError
|
- GIFs don't render inside unfurls and cause a TypeError
|
||||||
|
- Improve how the `muc_domain` setting is populated via service discovery
|
||||||
- #2746: Always reply to all iqs, even those not understood
|
- #2746: Always reply to all iqs, even those not understood
|
||||||
- #2868: Selected emoji is inserted into all open chat boxes
|
- #2868: Selected emoji is inserted into all open chat boxes
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ module.exports = function(config) {
|
||||||
{ pattern: "src/plugins/muc-views/tests/autocomplete.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/autocomplete.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/component.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/component.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/corrections.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/corrections.js", type: 'module' },
|
||||||
|
{ pattern: "src/plugins/muc-views/tests/disco.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/emojis.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/emojis.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/hats.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/hats.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/http-file-upload.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/http-file-upload.js", type: 'module' },
|
||||||
|
|
|
@ -8,7 +8,9 @@ import 'plugins/modal/index.js';
|
||||||
import './adhoc-commands.js';
|
import './adhoc-commands.js';
|
||||||
import MUCView from './muc.js';
|
import MUCView from './muc.js';
|
||||||
import { api, converse } from '@converse/headless/core';
|
import { api, converse } from '@converse/headless/core';
|
||||||
import { clearHistory, fetchAndSetMUCDomain, parseMessageForMUCCommands } from './utils.js';
|
import { clearHistory, parseMessageForMUCCommands } from './utils.js';
|
||||||
|
|
||||||
|
const { Strophe } = converse.env;
|
||||||
|
|
||||||
import './styles/index.scss';
|
import './styles/index.scss';
|
||||||
|
|
||||||
|
@ -58,6 +60,22 @@ converse.plugins.add('converse-muc-views', {
|
||||||
|
|
||||||
_converse.ChatRoomView = MUCView;
|
_converse.ChatRoomView = MUCView;
|
||||||
|
|
||||||
|
if (!api.settings.get('muc_domain')) {
|
||||||
|
// Use service discovery to get the default MUC domain
|
||||||
|
api.listen.on('serviceDiscovered', async (feature) => {
|
||||||
|
if (feature?.get('var') === Strophe.NS.MUC) {
|
||||||
|
if (feature.entity.get('jid').includes('@')) {
|
||||||
|
// Ignore full JIDs, we're only looking for a MUC service, not a room
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const identity = await feature.entity.getIdentity('conference', 'text');
|
||||||
|
if (identity) {
|
||||||
|
api.settings.set('muc_domain', Strophe.getDomainFromJid(feature.get('from')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
api.listen.on('clearsession', () => {
|
api.listen.on('clearsession', () => {
|
||||||
const view = _converse.chatboxviews.get('controlbox');
|
const view = _converse.chatboxviews.get('controlbox');
|
||||||
if (view && view.roomspanel) {
|
if (view && view.roomspanel) {
|
||||||
|
@ -67,14 +85,6 @@ converse.plugins.add('converse-muc-views', {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
api.listen.on('controlBoxInitialized', view => {
|
|
||||||
if (!api.settings.get('allow_muc')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fetchAndSetMUCDomain(view);
|
|
||||||
view.model.on('change:connected', () => fetchAndSetMUCDomain(view));
|
|
||||||
});
|
|
||||||
|
|
||||||
api.listen.on('chatBoxClosed', (model) => {
|
api.listen.on('chatBoxClosed', (model) => {
|
||||||
if (model.get('type') === _converse.CHATROOMS_TYPE) {
|
if (model.get('type') === _converse.CHATROOMS_TYPE) {
|
||||||
clearHistory(model.get('jid'));
|
clearHistory(model.get('jid'));
|
||||||
|
|
|
@ -74,23 +74,23 @@ export default BootstrapModal.extend({
|
||||||
this.loading_items = false;
|
this.loading_items = false;
|
||||||
|
|
||||||
BootstrapModal.prototype.initialize.apply(this, arguments);
|
BootstrapModal.prototype.initialize.apply(this, arguments);
|
||||||
if (api.settings.get('muc_domain') && !this.model.get('muc_domain')) {
|
|
||||||
this.model.save('muc_domain', api.settings.get('muc_domain'));
|
|
||||||
}
|
|
||||||
this.listenTo(this.model, 'change:muc_domain', this.onDomainChange);
|
this.listenTo(this.model, 'change:muc_domain', this.onDomainChange);
|
||||||
|
this.listenTo(this.model, 'change:feedback_text', () => this.render());
|
||||||
|
|
||||||
|
|
||||||
this.el.addEventListener('shown.bs.modal', () => api.settings.get('locked_muc_domain')
|
this.el.addEventListener('shown.bs.modal', () => api.settings.get('locked_muc_domain')
|
||||||
? this.updateRoomsList()
|
? this.updateRoomsList()
|
||||||
: this.el.querySelector('input[name="server"]').focus()
|
: this.el.querySelector('input[name="server"]').focus()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.model.save('feedback_text', '');
|
||||||
},
|
},
|
||||||
|
|
||||||
toHTML () {
|
toHTML () {
|
||||||
const muc_domain = this.model.get('muc_domain') || api.settings.get('muc_domain');
|
|
||||||
return tpl_muc_list(
|
return tpl_muc_list(
|
||||||
Object.assign(this.model.toJSON(), {
|
Object.assign(this.model.toJSON(), {
|
||||||
'show_form': !api.settings.get('locked_muc_domain'),
|
'show_form': !api.settings.get('locked_muc_domain'),
|
||||||
'server_placeholder': muc_domain ? muc_domain : __('conference.example.org'),
|
'server_placeholder': this.model.get('muc_domain') || __('conference.example.org'),
|
||||||
'items': this.items,
|
'items': this.items,
|
||||||
'loading_items': this.loading_items,
|
'loading_items': this.loading_items,
|
||||||
'openRoom': ev => this.openRoom(ev),
|
'openRoom': ev => this.openRoom(ev),
|
||||||
|
|
65
src/plugins/muc-views/tests/disco.js
Normal file
65
src/plugins/muc-views/tests/disco.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*global mock, converse */
|
||||||
|
|
||||||
|
describe("Service Discovery", function () {
|
||||||
|
|
||||||
|
it("can be used to set the muc_domain", mock.initConverse( ['discoInitialized'], {}, async function (_converse) {
|
||||||
|
const { u, $iq } = converse.env;
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
const IQ_ids = _converse.connection.IQ_ids;
|
||||||
|
const { api } = _converse;
|
||||||
|
|
||||||
|
expect(api.settings.get('muc_domain')).toBe(undefined);
|
||||||
|
|
||||||
|
await u.waitUntil(() => IQ_stanzas.filter(
|
||||||
|
(iq) => iq.querySelector(`iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]`)).length > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
let stanza = IQ_stanzas.find((iq) => iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]'));
|
||||||
|
const info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
|
||||||
|
stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'montague.lit',
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'id': info_IQ_id
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', { 'category': 'server', 'type': 'im'}).up()
|
||||||
|
.c('identity', { 'category': 'conference', 'name': 'Play-Specific Chatrooms'}).up()
|
||||||
|
.c('feature', { 'var': 'http://jabber.org/protocol/disco#info'}).up()
|
||||||
|
.c('feature', { 'var': 'http://jabber.org/protocol/disco#items'}).up();
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
|
|
||||||
|
const entities = await _converse.api.disco.entities.get();
|
||||||
|
expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
|
||||||
|
expect(entities.get(_converse.domain).identities.length).toBe(2);
|
||||||
|
expect(entities.get('montague.lit').features.where(
|
||||||
|
{'var': 'http://jabber.org/protocol/disco#items'}).length).toBe(1);
|
||||||
|
expect(entities.get('montague.lit').features.where(
|
||||||
|
{'var': 'http://jabber.org/protocol/disco#info'}).length).toBe(1);
|
||||||
|
|
||||||
|
stanza = await u.waitUntil(() => IQ_stanzas.filter(
|
||||||
|
iq => iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#items"]')).pop()
|
||||||
|
);
|
||||||
|
|
||||||
|
_converse.connection._dataRecv(mock.createRequest($iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'montague.lit',
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'id': IQ_ids[IQ_stanzas.indexOf(stanza)]
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
|
||||||
|
.c('item', { 'jid': 'chat.shakespeare.lit', 'name': 'Chatroom Service'})));
|
||||||
|
|
||||||
|
stanza = await u.waitUntil(() => IQ_stanzas.filter(
|
||||||
|
iq => iq.querySelector('iq[to="chat.shakespeare.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]')).pop()
|
||||||
|
);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest($iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'chat.shakespeare.lit',
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'id': IQ_ids[IQ_stanzas.indexOf(stanza)]
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', { 'category': 'conference', 'name': 'Play-Specific Chatrooms', 'type': 'text'}).up()
|
||||||
|
.c('feature', { 'var': 'http://jabber.org/protocol/muc'}).up()));
|
||||||
|
|
||||||
|
await u.waitUntil(() => _converse.api.settings.get('muc_domain') === 'chat.shakespeare.lit');
|
||||||
|
}));
|
||||||
|
});
|
|
@ -61,51 +61,6 @@ export async function destroyMUC (model) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setMUCDomain (domain, controlboxview) {
|
|
||||||
controlboxview.querySelector('converse-rooms-list')
|
|
||||||
.model.save('muc_domain', Strophe.getDomainFromJid(domain));
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMUCDomainFromDisco (controlboxview) {
|
|
||||||
/* Check whether service discovery for the user's domain
|
|
||||||
* returned MUC information and use that to automatically
|
|
||||||
* set the MUC domain in the "Add groupchat" modal.
|
|
||||||
*/
|
|
||||||
function featureAdded (feature) {
|
|
||||||
if (!feature) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (feature.get('var') === Strophe.NS.MUC) {
|
|
||||||
feature.entity.getIdentity('conference', 'text').then(identity => {
|
|
||||||
if (identity) {
|
|
||||||
setMUCDomain(feature.get('from'), controlboxview);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
api.waitUntil('discoInitialized')
|
|
||||||
.then(() => {
|
|
||||||
api.listen.on('serviceDiscovered', featureAdded);
|
|
||||||
// Features could have been added before the controlbox was
|
|
||||||
// initialized. We're only interested in MUC
|
|
||||||
_converse.disco_entities.each(entity => featureAdded(entity.features.findWhere({ 'var': Strophe.NS.MUC })));
|
|
||||||
})
|
|
||||||
.catch(e => log.error(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchAndSetMUCDomain (controlboxview) {
|
|
||||||
if (controlboxview.model.get('connected')) {
|
|
||||||
if (!controlboxview.querySelector('converse-rooms-list').model.get('muc_domain')) {
|
|
||||||
if (api.settings.get('muc_domain') === undefined) {
|
|
||||||
setMUCDomainFromDisco(controlboxview);
|
|
||||||
} else {
|
|
||||||
setMUCDomain(api.settings.get('muc_domain'), controlboxview);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getNicknameRequiredTemplate (model) {
|
export function getNicknameRequiredTemplate (model) {
|
||||||
const jid = model.get('jid');
|
const jid = model.get('jid');
|
||||||
if (api.settings.get('muc_show_logs_before_join')) {
|
if (api.settings.get('muc_show_logs_before_join')) {
|
||||||
|
|
|
@ -7,23 +7,17 @@
|
||||||
*/
|
*/
|
||||||
import "@converse/headless/plugins/muc/index.js";
|
import "@converse/headless/plugins/muc/index.js";
|
||||||
import './view.js';
|
import './view.js';
|
||||||
import { api, converse } from "@converse/headless/core";
|
import { converse } from "@converse/headless/core";
|
||||||
|
|
||||||
|
|
||||||
converse.plugins.add('converse-roomslist', {
|
converse.plugins.add('converse-roomslist', {
|
||||||
|
|
||||||
dependencies: ["converse-singleton", "converse-controlbox", "converse-muc", "converse-bookmarks"],
|
dependencies: [
|
||||||
|
"converse-singleton",
|
||||||
|
"converse-controlbox",
|
||||||
|
"converse-muc",
|
||||||
|
"converse-bookmarks"
|
||||||
|
],
|
||||||
|
|
||||||
initialize () {
|
initialize () { }
|
||||||
// Event handlers
|
|
||||||
api.listen.on('connected', async () => {
|
|
||||||
if (api.settings.get('allow_bookmarks')) {
|
|
||||||
await api.waitUntil('bookmarksInitialized');
|
|
||||||
} else {
|
|
||||||
await Promise.all([
|
|
||||||
api.waitUntil('chatBoxesFetched'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { _converse, api, converse } from "@converse/headless/core";
|
||||||
const { Strophe } = converse.env;
|
const { Strophe } = converse.env;
|
||||||
|
|
||||||
const RoomsListModel = Model.extend({
|
const RoomsListModel = Model.extend({
|
||||||
|
|
||||||
defaults: function () {
|
defaults: function () {
|
||||||
return {
|
return {
|
||||||
'muc_domain': api.settings.get('muc_domain'),
|
'muc_domain': api.settings.get('muc_domain'),
|
||||||
|
@ -12,6 +13,10 @@ const RoomsListModel = Model.extend({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
initialize () {
|
||||||
|
api.settings.listen.on('change:muc_domain', (muc_domain) => this.setDomain(muc_domain));
|
||||||
|
},
|
||||||
|
|
||||||
setDomain (jid) {
|
setDomain (jid) {
|
||||||
if (!api.settings.get('locked_muc_domain')) {
|
if (!api.settings.get('locked_muc_domain')) {
|
||||||
this.save('muc_domain', Strophe.getDomainFromJid(jid));
|
this.save('muc_domain', Strophe.getDomainFromJid(jid));
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
// connection_options: { 'worker': '/dist/shared-connection-worker.js' },
|
// connection_options: { 'worker': '/dist/shared-connection-worker.js' },
|
||||||
// persistent_store: 'IndexedDB',
|
// persistent_store: 'IndexedDB',
|
||||||
message_archiving: 'always',
|
message_archiving: 'always',
|
||||||
muc_domain: 'conference.chat.example.org',
|
// muc_domain: 'conference.chat.example.org',
|
||||||
muc_respect_autojoin: true,
|
muc_respect_autojoin: true,
|
||||||
view_mode: 'fullscreen',
|
view_mode: 'fullscreen',
|
||||||
websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
|
websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user